next up previous contents
Next: Atomowe operacje na potokach Up: Jednokierunkowe potoki z Unixa Previous: Tworzenie potoków w C   Contents

Potoki - prosta metoda!

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
   


next up previous contents
Next: Atomowe operacje na potokach Up: Jednokierunkowe potoki z Unixa Previous: Tworzenie potoków w C   Contents

2000-03-01


Poltronic