[英]How do I chain stdout in one child process to stdin in another child in C?
[英]How can i dynamically chain unix utility commands in C program wiring stdout of child process to stdin of parent process?
在下面的代碼中,我相信我正確地將子進程的 output 連接到父進程的輸入,但我可能錯了。 由於某種原因,當我調用 sort 時,shell 上的信息沒有正確顯示。 例如 sort 應該返回 Makefile combo combo.c combo.o
但是我得到了combo combo.c combo.o makefile
我還必須在父進程中重新運行程序並將所有 arguments 放回程序中(由子進程運行的argv[1]
除外)我嘗試將argv
字符串解析為另一個數組,但不知道該怎么做才能得到他們都進入下一個程序。 嘗試了execvp
,但出現錯誤,說明execvp
正在尋找char * const[]
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
int
main(int argc, char *argv[])
{
char buf[BUFSIZ];
char args[20][BUFSIZ];
int i, n;
if (argc < 2) {
fprintf(stderr, "Combo usage requires unix utility command argument\n");
exit(-1);
}
else if (argc == 2) {
execlp(argv[1], argv[1], NULL);
}
else {
strcpy(args[0], argv[0]);
for (i = 2; i <= argc - 1; i++)
strcpy(args[i - 1], argv[i]);
// for(i = 0; i < argc - 1; i++)
// printf("%s\n", args[i]);
pid_t pid;
int fd[2];
if (pipe(fd) < 0) {
perror("pipe failed");
return 1;
}
pid = fork();
if (pid < 0) {
perror("fork failed");
exit(-1);
}
else if (pid == 0) {
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
close(fd[0]);
execlp(argv[1], argv[1], NULL);
perror("exec failed");
exit(-1);
}
else {
wait(0);
dup2(fd[0], STDIN_FILENO);
close(fd[1]);
close(fd[0]);
execlp("./combo", "./combo", args[1], NULL);
perror("exec failed");
exit(-1);
}
}
return 0;
}
好吧,有幾個問題...
正如我在評論中提到的, dup2
的參數是相反的。
但是,主要問題是,雖然可以使用單個fork
[並從父級執行其中一個子級] 來執行此操作,但最好在循環中執行兩個fork
調用。
這樣, wait
調用 [復數] 可以由父級完成,而wait
不會干擾兩個子級之間的數據流。 這就是大多數 shell 的工作方式[我已經在這里回答了這個問題]。
所以,我不得不稍微重構你的代碼。 它編譯,但我沒有測試它。
請注意,對於給定的 pipe,例如: sender | receiver
sender | receiver
,這首先啟動發送者。 然后,啟動接收器。 換句話說,以從左到右的順序啟動程序。
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
int
main(int argc, char *argv[])
{
char buf[BUFSIZ];
char args[20][BUFSIZ];
int i, n;
if (argc < 2) {
fprintf(stderr, "Combo usage requires unix utility command argument\n");
return 1;
}
if (argc == 2) {
execlp(argv[1], argv[1], NULL);
perror("execlp");
return 2;
}
strcpy(args[0], argv[0]);
for (i = 2; i <= argc - 1; i++)
strcpy(args[i - 1], argv[i]);
// for(i = 0; i < argc - 1; i++)
// printf("%s\n", args[i]);
pid_t pid;
pid_t pids[2];
int fd[2];
if (pipe(fd) < 0) {
perror("pipe failed");
return 3;
}
// fork/exec our two children
for (int icld = 0; icld <= 1; ++icld) {
int ipipe = ! icld;
// do the fork
pid = fork();
// more elaborate programs might make use of this -- just to illustrate
pids[icld] = pid;
// fork failure ...
if (pid < 0) {
perror("fork failed");
return 4;
}
// parent ...
if (pid != 0)
continue;
// connect up pipe to correct end of child
dup2(ipipe,fd[ipipe]);
// close the extra pipe units
close(fd[1]);
close(fd[0]);
// execute the child
switch (ipipe) {
case 0: // receiver
execlp("./combo", "./combo", args[1], NULL);
break;
case 1: // sender
execlp(argv[1], argv[1], NULL);
break;
}
fprintf(stderr,"execlp failure for child %d/%d -- %s\n",
icld,ipipe,strerror(errno));
exit(5);
}
close(fd[0]);
close(fd[1]);
int status;
int bigcode = 0;
int curcode = 0;
// wait for all children to complete
while (1) {
pid = wait(&status);
if (pid <= 0)
break;
do {
// simple exit code
if (WIFEXITED(status)) {
curcode = WEXITSTATUS(status);
fprintf(stderr,"child %d -- exit %d\n",pid,curcode);
break;
}
// child got a signal [probably SIGSEGV]
if (WIFSIGNALED(status)) {
curcode = WTERMSIG(status);
fprintf(stderr,"child %d -- signal %d\n",pid,curcode);
curcode + 20;
break;
}
// stopped and/or continued -- we don't really care for this app
curcode = 19;
} while (0);
// remember the most severe error
if (curcode > bigcode)
bigcode = curcode;
}
return bigcode;
}
對於我創建的簡單 shell [已測試],請參閱我的答案: fd leak, custom Shell
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.