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, uruchamia 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 standardowych 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
Paweł Niewiadomski
2000-10-17