2011-07-15 93 views
1

我想重现shell中的管道。例如ls |排序 起初,我想管,但我不能让家长读什么样的孩子已经执行的结果是:C中的管道,fork和shell命令

//pipes essai 
# include <stdio.h> 
# include <stdlib.h> 
# include <unistd.h> 
# include <sys/types.h> 
# include <sys/wait.h> 
# include <assert.h> 
# include <string.h> 
# include <sys/stat.h> 
# include <fcntl.h> 

enum { 
MaxLigne = 1024, // longueur max d'une ligne de commandes 
MaxMot = MaxLigne/2, // nbre max de mot dans la ligne 
MaxDirs = 100, // nbre max de repertoire dans PATH 
MaxPathLength = 512, 
// longueur max d'un nom de fichier 
}; 

void decouper(char *, char *, char **, int); 
int spawn(char * pathname, char * mot[]); 

# define PROMPT "? " 

int main(int argc, char * argv[]) { 
char ligne[MaxLigne]; 
char pathname[MaxPathLength]; 
char * mot[MaxMot]; 
char * dirs[MaxDirs]; 
int i, tmp, x; 
int fd[2]; 
int t, res = 0; 
char buf[1024]; 
char * mot2[10]; 

/* Decouper PATH en repertoires */ 
decouper(getenv("PATH"), ":", dirs, MaxDirs); 

/* read the command lines and try to execute them */ 
for (printf(PROMPT); fgets(ligne, sizeof ligne, stdin) != 0; printf(PROMPT)) { 
    decouper(ligne, " \t\n", mot, MaxMot); 
    if (mot[0] == 0) // empty line 
     continue; 

     //launch the pipe 
     int p=pipe(fd); 
     assert(p>=0); 


     tmp = fork(); // launch the pipe process 
     if (tmp < 0) { 
      perror("fork"); 
      continue; 
     } 

     if (tmp != 0) { // parent wait for end of child 

      //close this side of the pipe 
      close(fd[1]); 
      //waiting 
      while (wait(0) != tmp) 
       ; 
      //when finish waiting read what the child has written in the pipe 
      read(fd[0], buf, sizeof(buf)); 
      //print the result 
      printf("read %s\n", buf); 
      //get back the hand to the user 
      continue; 

     }else if (tmp==0){ 

     // child 

     //close this side of the pipe 
     close(fd[0]); 
     //close stdout 
     t=close(1); 
     //make sur stdout is closed 
     assert(t>=0); 
     //open the pipe for writing in it instead of in the stdout 
     FILE * sortie=fdopen(fd[1], O_WRONLY); 
     //make sure it is ok 
     assert(sortie!=NULL); 

     //try to execute the command 
     for (i = 0; dirs[i] != 0; i++) { 
      snprintf(pathname, sizeof pathname, "%s/%s", dirs[i], mot[0]); 
      execv(pathname, mot); 

     } 
     } 

     // if exec was unsuccessful 
     fprintf(stderr, "%s: not found\n", mot[0]); 
     exit(1); 

} 

    printf("Bye\n"); 
    return 0; 

} 

void decouper(char * ligne, char * separ, char * mot[], int maxmot){ 
int i; 

mot[0] = strtok(ligne, separ); 
for(i = 1; mot[i - 1] != 0; i++){ 
if (i == maxmot){ 
    fprintf(stderr, "Erreur dans la fonction decouper: trop de mots\n"); 
    mot[i - 1] = 0; 
} 
mot[i] = strtok(NULL, separ); 
} 
} 

没有与此行FILE *架次= fdopen(FD [问题1],O_WRONLY);

pipe1.c:在函数 '主': pipe1.c:81:4:警告:传递的 'fdopen' 参数2时将整数指针,未作铸造 /usr/include/stdio.h:303 :14:注意:期望的'const char *'但参数的类型为'int'

但是我怎样才能让孩子输出管道? freopen不起作用

我得到的结果: ? ls 阅读

这意味着当然没有读。我能做什么我现在真的没有想法了吗? 非常感谢您提前

+0

fdopen采用字符串模式,就像fopen一样。尝试用fdopen替换(fd [1],“w”)。这会有帮助吗? – theamk

回答

1

您在fdopen的签名与open的签名混淆。 fdopen需要const char*作为其第二个参数。尝试

FILE * sortie=fdopen(fd[1], "w"); 

参考:


编辑:看来,您正在使用 fdopen对于没有正当理由。具体来说,在初始化后我没有看到 sortie的使用。

我认为你正在尝试为exec'd程序设置标准。如果是这样的话,你应该使用dupdup2

close(fd[0]); 
close(1); 
dup(fd[1]); 
close(fd[1]); 

//try to execute the command 
... as before 

参考:

+0

很多我用“W”取代它,我不再犯错,但我得到这个错误:LS:erreur d'écriture:Mauvais descripteur de fichier阅读这意味着基本上错误的文件描述符 – vallllll

+0

至于freopen我可以'因为:FILE * freopen(const char * path,const char * mode,FILE * stream);所以我需要一个文件名,我只有一个文件描述符,有没有办法使用它? – vallllll

+0

@vallllll - 对不起,我看到'fdopen'的错误使用,并没有看得更远。你不想'fdopen',它不会做你认为它的事。你想要'dup'或者'dup2'。看我的编辑。 –

2

一个单独的问题...

如果孩子写了一个很多输出到管道,它会阻塞,直到父母读取一些。管道容量有限(懒惰妨碍我寻找典型的限制)。

您的父母代码在孩子退出之前不会进行任何阅读。但是,如果孩子阻塞管道输出,它将永远不会退出。僵局!

+0

当天的限制是10 x 512.我不知道现代限制是什么;写得好的程序不需要知道。 –

+0

这是ls命令的输出:arriere_plan ch-spawn.c decouper.c moncd.c验证 arriere_plan.c co-main.c moncd pipe1 如此喜欢6个文件它不能这么受限制? – vallllll

+0

我没有声称这是唯一的问题。只是一个问题。 5K左右是我对老学校限制的记忆。 –