Реализация трубы в C
Я пытаюсь реализовать канал в C. eg - $ ls | wc | wc
Я написал следующий код -
#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
void run_cmd(char *cmd, int* fd_in, int* fd_out)
{
int c = fork();
if (c==0)
{
if (fd_in != NULL)
{
close(fd_in[1]);
dup2(fd_in[0], 0);
}
if (fd_out != NULL)
{
close(fd_out[0]);
dup2(fd_out[1],1);
}
execlp(cmd, cmd, NULL);
}
}
int main(int argc, char **argv)
{
int fd_1[2], fd_2[2], i;
pipe(fd_1);
pipe(fd_2);
run_cmd(argv[1], NULL, fd_1);
for( i=2; i<argc-1; i++)
{
if (i%2 == 0)
run_cmd(argv[i], fd_1, fd_2);
else
run_cmd(argv[i], fd_2, fd_1);
}
if (i%2 == 0)
run_cmd(argv[i], fd_1, NULL);
else
run_cmd(argv[i], fd_2, NULL);
}
Это отлично работает с двумя аргументами, например - $./a.out ls wc
Но когда я пытаюсь использовать более двух аргументов, это не работает.
Кто-нибудь может сказать, что случилось с моим кодом, или любым другим способом сделать это. Любая помощь будет высоко оценена.
Ответы
Ответ 1
Это практически не проверяет ошибки, но почему так сложно?
int main (int argc, char ** argv) {
int i;
for( i=1; i<argc-1; i++)
{
int pd[2];
pipe(pd);
if (!fork()) {
dup2(pd[1], 1); // remap output back to parent
execlp(argv[i], argv[i], NULL);
perror("exec");
abort();
}
// remap output from previous child to input
dup2(pd[0], 0);
close(pd[1]);
}
execlp(argv[i], argv[i], NULL);
perror("exec");
abort();
}
Ответ 2
Если вас все еще интересует, почему ваш источник не работал (решение Сергея в любом случае лучше):
Проблема заключается не в закрытии стороны записи fd_1
в родительском процессе. Таким образом, как argv[1]
, так и родительские были писателями этого канала, что вызвало путаницу. Пожалуйста, не запрашивайте более подробную информацию (особенно, почему проблема не возникает, если вы используете только один канал), но исходный исходный код будет работать с древовидными процессами, если вы просто добавите close( fd_1[1] );
после первого вызова run_cmd()