Jeżeli powyższe przykłady wydają ci się zakręconą metodą tworzenia potoków, można zrobić to w inny sposób.
FUNKCJA Z BIBLIOTEKI: popen();
PROTOTYP: FILE *popen ( char *komenda, char *typ);
ZWRACA: nowy strumień do pliku jeżeli sukces
NULL jeżeli fork() lub pipe() zawiodło
UWAGI: tworzy potok oraz przeprowadza fork/exec używając "komendy"
Ta standardowa funckja biblioteki tworzy potok wywołując wewnętrznie pipe(). Po tym forkuje proces potomny, uruczamia powłokę Bourne'a oraz uruchamia argument "komenda" korzystając z powłoki. Kierunek przepływu danych określany jest przez argument "typ", który może przybierać wartości "r" ( odczyt ) lub "w" ( zapis ). Nie można ich użyć jednocześnie. Jeżeli cię podkusi i podasz "rw" pod Linuxem potok zostanie otwarty w trybie wskazanym przez pierwszą literę, czyli w tym wypadku w trybie odczytu.
Przez to, że ta funkcja odwala za ciebie większość roboty tracisz kontrolę, którą miałeś posługując się pipe() i samemu forkując. Z drugiej strony dzięki temu, iż powłoka Bourne'a jest używana bezpośrednio możesz korzystać z dobrodziejstwa masek oraz rozwijania metaznaków.
Potoki otwierane za pomocą popen() muszą zostać zamknięte funkcją pclose(). Prawdopodobnie już spostrzegłeś podobieństwo popen/pclose do standartowych funkcji strumieniowego We/Wy do plików - fopen() i fclose().
FUNKCJA Z BIBLIOTEKI: pclose();
PROTOTYP: int pclose( FILE *stream );
ZWRACA: status wyjściowy wywołania wait4()
-1 jeżeli "stream" jest nieprawidłowy lub zawiodło wait4()
UWAGI: czeka na zakończenie operacji na potoku, póżniej zamyka potok
Funkcja pclose() uruchamia wait4() dla procesu utworzonego przez popen(). Po powrocie z wait4() niszczy potok oraz strumień do pliku.
Rozważ poniższy przykład, który otwiera potok dla komendy sort, wykorzystując ją sortuje tablicę łańcuchów:
/*****************************************************************************
Zaczerpnięto z "Linux Programmer's Guide - Rozdział 6"
(C)opyright 1994-1995, Scott Burkett
*****************************************************************************
MODUŁ: popen1.c
*****************************************************************************/
#include <stdio.h>
#define MAXSTRS 5
int main(void)
{
int cntr;
FILE *pipe_fp;
char *strings[MAXSTRS] = { "echo", "bravo", "alpha",
"charlie", "delta"};
/* Tworzymy jednokierunkowy potok za pomocą popen() */
if (( pipe_fp = popen("sort", "w")) == NULL)
{
perror("popen");
exit(1);
}
/* Pętla przetwarzająca */
for(cntr=0; cntr<MAXSTRS; cntr++) {
fputs(strings[cntr], pipe_fp);
fputc('\n', pipe_fp);
}
/* Zamykamy potok */
pclose(pipe_fp);
return(0);
}
Dzięki temu, iż popen() korzysta z powłoki wszystkie rozwinięcia znaków i metaznaków są dostępne! Możemy również korzystać z bardziej zaawansowanych technik jak przekierowywanie, używanie potoków. Popatrz na poniższe przykłady:
popen("ls ~scottb", "r");
popen("sort > /tmp/foo", "w");
popen("sort | uniq | more", "w");
Jako następny przykład programik, który otwiera dwa potoki ( jeden do ls, drugi do sort ):
/*****************************************************************************
Zaczerpnięto z "Linux Programmer's Guide - Rozdział 6"
(C)opyright 1994-1995, Scott Burkett
*****************************************************************************
MODUŁ: popen2.c
*****************************************************************************/
#include <stdio.h>
int main(void)
{
FILE *pipein_fp, *pipeout_fp;
char readbuf[80];
/* Tworzymy jednokierunkowy potok za pomocą popen() */
if (( pipein_fp = popen("ls", "r")) == NULL)
{
perror("popen");
exit(1);
}
/* Tworzymy jednokierunkowy potok za pomocą popen() */
if (( pipeout_fp = popen("sort", "w")) == NULL)
{
perror("popen");
exit(1);
}
/* Przetwarzanie */
while(fgets(readbuf, 80, pipein_fp))
fputs(readbuf, pipeout_fp);
/* Zamknięcie potoków */
pclose(pipein_fp);
pclose(pipeout_fp);
return(0);
}
Oto nasz końcowy przykład użycie popen(). Tworzymy program, który tworzy potok między podaną komendą i plikiem:
/*****************************************************************************
Zaczerpnięto z "Linux Programmer's Guide - Rozdział 6"
(C)opyright 1994-1995, Scott Burkett
*****************************************************************************
MODUŁ: popen3.c
*****************************************************************************/
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *pipe_fp, *infile;
char readbuf[80];
if( argc != 3) {
fprintf(stderr, "UŻYCIE: popen3 [komenda] [plik]\n");
exit(1);
}
/* Otwieramy plik wejściowy */
if (( infile = fopen(argv[2], "rt")) == NULL)
{
perror("fopen");
exit(1);
}
/* Tworzymy jednokierunkowy potok za pomocą popen() */
if (( pipe_fp = popen(argv[1], "w")) == NULL)
{
perror("popen");
exit(1);
}
do {
fgets(readbuf, 80, infile);
if(feof(infile)) break;
fputs(readbuf, pipe_fp);
} while(!feof(infile));
fclose(infile);
pclose(pipe_fp);
return(0);
}
Wyprubuj program:
popen3 sort popen3.c
popen3 cat popen3.c
popen3 more popen3.c
popen3 cat popen3.c | grep main