Я знаю, что эта тема была опубликована довольно часто, но я хочу взять ее в другом направлении.Я хотел бы написать программу, которая имеет функциональность конвейерной оболочки, например, cmd1 |cmd2 |cmd3 трубопроводов и перенаправлений.Я прочитал страницы типа , , , и , для справки.И эти решения прекрасно работают для «горизонтальной конвейеризации», но я бы хотел реализовать ее «вертикально».Для того, чтобы моя оболочка была вертикальной, каждый процесс 'команда' должен иметь своего родителя (предыдущая команда).Таким образом, каждая команда, которая должна быть выполнена, порождается из предыдущей.Проблема, с которой я столкнулся, заключается в том, что когда я выполняю рекурсию в потомке (а не в родителе, как в примерах), программа выполняется нормально, но затем зависает, и я должен нажать Enter, чтобы перекомпоновать мою оболочку.Мне любопытно, почему это не так и как это исправить.
static void exec_pipeline(size_t pos, int in_fd) {
// Invalid Pipe has issues
if (newargv[pipe_commands[pos+1]] == NULL)
report_error_and_exit("Invalid pipe");
/* last command, pipe_command conatins indices of commands to execute */
if (pipe_commands[pos + 1] == 0) {
redirect(in_fd, STDIN_FILENO); /* read from in_fd, write to STDOUT */
execvp(newargv[pipe_commands[pos]], newargv + pipe_commands[pos]);
report_error_and_exit("execvp last command");
}
else { /* $ <in_fd cmds[pos] >fd[1] | <fd[0] cmds[pos+1] ... */
int fd[2]; /* output pipe */
if (pipe(fd) == -1)
report_error_and_exit("pipe");
switch(fork()) {
case -1:
report_error_and_exit("fork");
case 0: /* parent: execute the rest of the commands */
CHK(close(fd[1])); /* unused */
CHK(close(in_fd)); /* unused */
exec_pipeline(pos + 1, fd[0]); /* execute the rest */
default: /* child: execute current command `cmds[pos]` */
child = 1;
CHK(close(fd[0])); /* unused */
redirect(in_fd, STDIN_FILENO); /* read from in_fd */
redirect(fd[1], STDOUT_FILENO); /* write to fd[1] */
execvp(newargv[pipe_commands[pos]], newargv + pipe_commands[pos]);
report_error_and_exit("execvp");
}
}
}
void report_error_and_exit(const char *msg) {
perror(msg);
(child ? _exit : exit)(EXIT_FAILURE);
}
/* move oldfd to newfd */
void redirect(int oldfd, int newfd) {
if (oldfd != newfd) {
if (dup2(oldfd, newfd) != -1)
CHK(close(oldfd));
else
report_error_and_exit("dup2");
}
}
CHK очень похож на assert, определен в файле с именем CHK.h и выглядит так, если вам интересно:
do {if((x) == -1)\
{fprintf(stderr,"In file %s, on line %d:\n",__FILE__,__LINE__);\
fprintf(stderr,"errno = %d\n",errno);\
perror("Exiting because");\
exit(1);\
}\
} while(0)