2016-11-23 13 views
2

私は、コマンドを実装するプログラムを書くことをしようとしている:名前STDINをchaning Cにおけるパイプ、フォークで標準出力()

ls -al | tr 'a-z' 'A-Z' | grep X > testing 

は基本的に私はそこC.で二度配管を使用する方法を学びたいです私たちが1つの '|'だけを使っている投稿がたくさんあります。私は、1つの '|'残念ながらそれは動作しません。コードがあります。

#include <stdio.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <fcntl.h> 
#define MAX 512 
int main(int argc,char** argv){ 
    int pdesk[2]; 
    int pipedesk[2]; 
    if(pipe(pipedesk)==-1 || pipe(pdesk)==-1){ 
     perror("Pipe"); 
     exit(1); 
    } 
    switch(fork()){ 
     case -1 : 
       perror("Creating process"); 
       exit(1); 
     case 0: 
       dup2(pdesk[1],STDOUT_FILENO); 
       close(pdesk[1]); 
       execlp("ls","ls","-al",NULL); 
       perror("ls"); 
       exit(1); 
     default: { 
       if(fork()==0){ 
        if(fork()==0){ 
         dup2(pdesk[0],STDIN_FILENO); 
         close(pdesk[0]); 
         dup2(pipedesk[1],STDOUT_FILENO); 
         close(pipedesk[1]); 
         execlp("tr","tr","a-z","A-Z",NULL); 
         perror("tr"); 
         exit(1); 
        } 
        dup2(pipedesk[0],STDIN_FILENO); 
        close(pipedesk[0]); 
        int desk=open("testing",O_WRONLY|O_CREAT,0640); 
        if(desk==-1){ 
         perror("opening file"); 
         exit(1); 
        } 
        dup2(desk,STDOUT_FILENO); 
        if(close(desk)==-1){ 
         perror("closing file"); 
         exit(1); 
        } 
        execlp("grep","grep","X",NULL); 
        perror("grep"); 
        exit(1); 
       } 
//    wait(NULL); 

     } 
     return 0; 
    } 
} 
+1

は動作しません? –

+0

[* magic numbers *](https://en.wikipedia.org/wiki/Magic_number_(プログラミング))は使用しないでください。代わりに 'STDIN_FILENO'や' STDOUT_FILENO'のような定義済みのマクロを使用してください。また、重要なヘッダーファイルインクルードがありません。 –

+0

あなたの問題については、* 2本のパイプが必要です。既存のパイプを再利用することはできません。 –

答えて

0

私は、信号処理が適切であるとは思いません。適切なのは、パイプが適切に閉じられていることを確認することです。書き込み終了のプロセスがある場合、プロセスはパイプの読み取り側でEOFを取得しません。それには現在のプロセスが含まれます。プロセスがパイプの読み取りと書き込みの両方の端を開いている場合、理論的には書き込み可能なプロセスが存在するため、パイプの読み取り側でEOFを取得することはありません。したがって、そのようなプロセスはパイプ上のread()に永続的に掛かります。

あなたのコードのこのバージョンは、私のために正常に動作します:

#include <fcntl.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <sys/wait.h> 
#include <unistd.h> 

int main(void) 
{ 
    int pdesk[2]; 
    int pipedesk[2]; 
    int pid; 

    if (pipe(pipedesk) == -1 || pipe(pdesk) == -1) 
    { 
     perror("Pipe"); 
     exit(1); 
    } 
    //fprintf(stderr, "PID %d: controller\n", (int)getpid()); 

    switch (pid = fork()) 
    { 
    case -1: 
     perror("Creating process"); 
     exit(1); 
    case 0: 
     //fprintf(stderr, "PID %d: will be 'ls'\n", (int)getpid()); 
     dup2(pdesk[1], STDOUT_FILENO); 
     close(pdesk[0]);  // JL 
     close(pdesk[1]); 
     close(pipedesk[0]);  // JL 
     close(pipedesk[1]);  // JL 
     execlp("ls", "ls", "-al", (char *)NULL); 
     perror("ls"); 
     exit(1); 
    default: 
     //fprintf(stderr, "PID %d: ls process PID = %d\n", (int)getpid(), pid); 
     if ((pid = fork()) == 0) 
     { 
      //fprintf(stderr, "PID %d: about to fork 'tr'\n", (int)getpid()); 
      if ((pid = fork()) == 0) 
      { 
       //fprintf(stderr, "PID %d: will be 'tr'\n", (int)getpid()); 
       dup2(pdesk[0], STDIN_FILENO); 
       close(pdesk[0]); 
       close(pdesk[1]);  // JL 
       dup2(pipedesk[1], STDOUT_FILENO); 
       close(pipedesk[0]);  // JL 
       close(pipedesk[1]); 
       execlp("tr", "tr", "a-z", "A-Z", (char *)NULL); 
       perror("tr"); 
       exit(1); 
      } 
      //fprintf(stderr, "PID %d: about to exec 'grep'\n", (int)getpid()); 
      dup2(pipedesk[0], STDIN_FILENO); 
      close(pdesk[0]);  // JL 
      close(pdesk[1]);  // JL 
      close(pipedesk[0]); 
      close(pipedesk[1]);  // JL 
      int desk = open("testing", O_WRONLY | O_CREAT, 0644); 
      if (desk == -1) 
      { 
       perror("opening file"); 
       exit(1); 
      } 
      dup2(desk, STDOUT_FILENO); 
      if (close(desk) == -1) 
      { 
       perror("closing file"); 
       exit(1); 
      } 
      execlp("grep", "grep", "X", (char *)NULL); 
      perror("grep"); 
      exit(1); 
     } 

     //fprintf(stderr, "PID %d: closing pipes\n", (int)getpid()); 
     close(pdesk[0]);  // JL 
     close(pdesk[1]);  // JL 
     close(pipedesk[0]);  // JL 
     close(pipedesk[1]);  // JL 

     break; 
    } 

    int status; 
    int corpse; 
    while ((corpse = wait(&status)) != -1) 
     fprintf(stderr, "PID %d: child %d died 0x%.4X\n", (int)getpid(), corpse, status); 

    return 0; 
} 

注すべての線が近い操作です// JLをマーク。おそらくあなたが離れていくことができるのは間違いありませんが(最初の子供のものはおそらく「オプション」です)、使用していないすべてのパイプを日常的に閉じておくべきです。特に、元の親プロセスのクローズ(最後の4つ)は重要です。複数のパイプで作業するときに十分なパイプ記述子を閉じていない

は、最も一般的なミスの一つです。標準の入力または出力をパイプディスクリプタを複製するdup2()(又はdup())を使用する場合、一般的に、元のパイプの両方端を閉じなければなりません。また、プロセスがパイプ記述子をまったく使用していない場合は、それらを閉じる必要があります。プログラムから

出力例:

$ ./pp61 
PID 35665: child 35666 died 0x0000 
PID 35665: child 35667 died 0x0000 
$ 

testingファイルのサンプル内容:ここ

DRWXR-XR-X 44 JLEFFLER STAFF 1496 NOV 23 17:28 . 
DRWXR-XR-X 137 JLEFFLER STAFF 4658 NOV 23 17:28 .. 
DRWXR-XR-X 18 JLEFFLER STAFF 612 OCT 23 20:00 .GIT 
DR-XR-XR-X 4 JLEFFLER STAFF 136 AUG 14 23:27 SAFE 
DRWXR-XR-X 35 JLEFFLER STAFF 1190 NOV 23 09:19 UNTRACKED 
-RW-R--R-- 1 JLEFFLER STAFF  81 NOV 20 20:53 ANIMALS.TXT 
DRWXR-XR-X 3 JLEFFLER STAFF 102 SEP 12 00:03 DOC 
DRWXR-XR-X 8 JLEFFLER STAFF 272 NOV 10 20:58 ETC 
DRWXR-XR-X 17 JLEFFLER STAFF 578 JUL 15 19:06 INC 
-RW-R--R-- 1 JLEFFLER STAFF 1217 NOV 21 21:26 IX37.SQL 
DRWXR-XR-X 5 JLEFFLER STAFF 170 JUL 9 23:47 LIB 
-RWXR-XR-X 1 JLEFFLER STAFF 9052 NOV 19 13:01 LL73 
DRWXR-XR-X 3 JLEFFLER STAFF 102 NOV 6 15:40 LL73.DSYM 
-RWXR-XR-X 1 JLEFFLER STAFF 8896 NOV 6 10:38 LL83 
DRWXR-XR-X 3 JLEFFLER STAFF 102 NOV 6 10:10 LL83.DSYM 
-RW-R--R-- 1 JLEFFLER STAFF 108 NOV 20 20:53 NEWANIMAL.TXT 
-RWXR-XR-X 1 JLEFFLER STAFF 9124 NOV 20 20:38 PD43 
DRWXR-XR-X 3 JLEFFLER STAFF 102 NOV 20 20:38 PD43.DSYM 
-RWXR-XR-X 1 JLEFFLER STAFF 9148 NOV 23 17:28 PP61 
DRWXR-XR-X 3 JLEFFLER STAFF 102 NOV 23 14:11 PP61.DSYM 
-RWXR-XR-X 1 JLEFFLER STAFF 9016 NOV 23 11:07 RS19 
DRWXR-XR-X 3 JLEFFLER STAFF 102 NOV 23 10:03 RS19.DSYM 
DRWXR-XR-X 146 JLEFFLER STAFF 4964 OCT 9 17:06 SRC 
-RWXR-XR-X 1 JLEFFLER STAFF 8760 NOV 23 13:12 STP83 
DRWXR-XR-X 3 JLEFFLER STAFF 102 NOV 23 13:04 STP83.DSYM 
DRWXR-XR-X 6 JLEFFLER STAFF 204 NOV 6 21:52 TMP 
-RWXR-XR-X 1 JLEFFLER STAFF 8808 NOV 23 10:38 TR37 
DRWXR-XR-X 3 JLEFFLER STAFF 102 NOV 23 10:38 TR37.DSYM 
-RWXR-XR-X 1 JLEFFLER STAFF 26772 NOV 21 20:18 XY73 
DRWXR-XR-X 3 JLEFFLER STAFF 102 NOV 21 20:18 XY73.DSYM 
-RW-R--R-- 1 JLEFFLER STAFF 467 NOV 21 20:18 XY73.L 
2

パイプのもう一方の端が消えると、プロセスはデフォルトでプロセスを終了するSIGPIPEを受け取ります。

だから、少なくともそれを無視するべきです!

signal(SIGPIPE, SIG_IGN); 

クリーンにするには、現在のプロセスで使用しないパイプの端をすべて閉じる必要があります。例えば

case 0: 
    close(pdesk[0]); 
    close(pipedesk[0]); 
    close(pipedesk[1]); 
+0

ありがとうございます)。シグナル(SIGPIPE、SIG_IGN)を加えた後、私のプログラムはSIGPIPEシグナを作成します。私はを追加し、main()の先頭にこのコマンドを追加しましたが、悲しいことに何も変わりません。 – ogarogar

0

が理解しやすい実装です。すべてのプロセスがパイプのもう一方の端を閉じていたとき、パイプの

一端が閉じられます。したがって、現在のプロセスでは役に立たないすべてのパイプを閉じることは非常に重要です。

#include <unistd.h> 
#include <stdio.h> 
#include <memory.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <signal.h> 

void closeAll(const int * fd_to_close){ 
    int i = 0; 
    while(1){ 
     int fd = fd_to_close[i]; 
     if(fd == -1){ 
      break; 
     } 
     close(fd); 
     i++; 
    } 
} 

pid_t forkExec(int my_stdin, int my_stdout, int my_stderr, char *const argv[], const int* fd_to_close){ 
    pid_t child = fork(); 

    if(child != 0){ 
     return child; 
    } 

    if(my_stdin != STDIN_FILENO){ 
     dup2(my_stdin, STDIN_FILENO); 
    } 
    if(my_stdout != STDOUT_FILENO){ 
     dup2(my_stdout, STDOUT_FILENO); 
    } 
    if(my_stderr != STDERR_FILENO){ 
     dup2(my_stderr, STDERR_FILENO); 
    } 

    closeAll(fd_to_close); 

    execvp(argv[0], argv); 

    perror("Executing "); 

    exit(1); 
} 

void waitFor(pid_t child){ 
    int status; 
    pid_t w = waitpid(child, &status, 0); 
    if(w == -1){ 
     perror("child "); 
    } else { 
     printf("Exit status of child %d was %d, killed by signal %d %s\n", (int) child, WEXITSTATUS(status), WTERMSIG(status), WCOREDUMP(status) ? "with coredump" : ""); 
    } 
} 

void main(int argc, char**argv){ 
    int pipe1[2]; 
    int pipe2[2]; 
    int fd_to_close[10]; 

    signal(SIGPIPE, SIG_IGN); 

    if(pipe(pipe1)==-1 || pipe(pipe2)==-1){ 
     perror("Pipe"); 
     exit(1); 
    } 

    fd_to_close[0] = pipe1[0]; 
    fd_to_close[1] = pipe1[1]; 
    fd_to_close[2] = pipe2[0]; 
    fd_to_close[3] = pipe2[1]; 
    fd_to_close[4] = -1; 

    char* cmd1[] = {"ls", "-al", NULL}; 
    char* cmd2[] = {"tr", "a-z", "A-Z", NULL}; 
    char* cmd3[] = {"grep", "X", NULL}; 

    pid_t child1 = forkExec(STDIN_FILENO, pipe1[1],  STDERR_FILENO, cmd1, fd_to_close); 
    pid_t child2 = forkExec(pipe1[0],  pipe2[1],  STDERR_FILENO, cmd2, fd_to_close); 
    pid_t child3 = forkExec(pipe2[0],  STDOUT_FILENO, STDERR_FILENO, cmd3, fd_to_close); 

    // Very important : 
    closeAll(fd_to_close); 

    printf("pid of %s is %d\n", cmd1[0], (int)child1); 
    printf("pid of %s is %d\n", cmd2[0], (int)child2); 
    printf("pid of %s is %d\n", cmd3[0], (int)child3); 

    waitFor(child1); 
    waitFor(child2); 
    waitFor(child3); 
} 
関連する問題