Implementación de múltiples tuberías utilizando la llamada al sistema fork () execvp () wait () pipe () – simplemente no funciona

Necesito implementar mi shell que maneja múltiples comandos de tubería. Por ejemplo, necesito ser capaz de manejar esto: ls | grep -i cs340 | sort | uniq | cut -c 5 ls | grep -i cs340 | sort | uniq | cut -c 5 ls | grep -i cs340 | sort | uniq | cut -c 5 . Supongo que el problema es que no estoy pasando la salida del comando anterior a la entrada del siguiente comando. Cuando ejecuto mi código, no me da salida. Estoy usando este pseudo código:

 for cmd in cmds if there is a next cmd pipe(new_fds) fork if child if there is a previous cmd dup2(old_fds[0], 0) close(old_fds[0]) close(old_fds[1]) if there is a next cmd close(new_fds[0]) dup2(new_fds[1], 1) close(new_fds[1]) exec cmd || die else if there is a previous cmd close(old_fds[0]) close(old_fds[1]) if there is a next cmd old_fds = new_fds if there are multiple cmds close(old_fds[0]) close(old_fds[1]) 

Aquí está el código fuente de la función que maneja múltiples tuberías.

 void execute_multiple_commands(struct command ** commands_to_exec, int num_commands_p) { pid_t status; int i, err; int new_fd[2], old_fd[2]; pid_t pid, cpid; // creating child process if ( (cpid = fork()) == -1) { fprintf(stderr, "Could not create child process, exiting..."); exit(1); } if (cpid == 0) // in the child process we run multiple pipe handling { for (i = 0; i < num_commands_p; i++) // for each cmd in cmds { if (i+1 < num_commands_p) // if there is next cmd pipe(new_fd); if ( (pid = fork()) == -1) { fprintf(stderr, "Could not create child process, exiting..."); exit(1); } if (pid == 0) // if child { if (i != 0) // if there is a previous command { dup2(old_fd[0], 0); // setting up old_pipe to input into the child close(old_fd[0]); close(old_fd[1]); } if (i+1 args[0], commands_to_exec[i]->args); status = err; exit(err); } } else { waitpid(pid, &status, 0); if (status == -1) exit(1); if (i != 0) // if there a previous command { close(old_fd[0]); close(old_fd[1]); } if (i+1 < num_commands_p) // if there a next cmd { old_fd[0] = new_fd[0]; old_fd[1] = new_fd[1]; } exit(0); } // end if } // end for if (i) // if there a multiple commands { close(old_fd[0]); close(old_fd[1]); } } else // in the parent process we are waiting for child to handle multiple pipes waitpid(cpid, &status, 0); } 

La función execvp() toma un conjunto de estructuras. He comprobado todas mis partes de análisis, y funciona bien. Es la función execute_multiple_commands() que estoy teniendo problemas.

Aquí está el código para struct:

 // name: command // desc: holds one command (meaning that it can be // more than one token in that command) // "ls -la" will be an example of one command // holds num of tokens in command array struct command { char ** args; int num_args; }; 

Sugiero una nueva estrategia, R2:

 function do(commands) if commands is of size 1 exec commands[0] || die split commands into c1 (first command) c2 (the rest of them) open if fork close input end of pipe dup output of pipe to stdin do (c2) || die close output end of pipe dup input of pipe to stdout exec c1 || die 

Usar una función recursiva, especialmente si mantienes una lista, te ayudará a simplificar tu lógica. Aquí realmente no tiene que preocuparse por la profundidad de la stack, ya que de todos modos se sobrescribirá todo su espacio de direcciones.

En otras noticias, desde la página del manual :

Después de un retorno exitoso de una de estas llamadas al sistema, los descriptores de archivos antiguos y nuevos se pueden usar indistintamente. Se refieren a la misma descripción de archivo abierto (consulte abrir (2)) y, por lo tanto, comparten el desplazamiento del archivo y las banderas de estado del archivo; por ejemplo, si el desplazamiento del archivo se modifica utilizando lseek (2) en uno de los descriptores, el desplazamiento también se cambia para el otro.

¿Qué significa cuando dices que estás cerrando los dos extremos de la tubería? Realmente lo está cerrando, y el estándar de entrada / salida que su progtwig pretende usar.

-> MUCHO DESPUÉS EDITAR <-

Como Jonathan Leffler señaló, la información anterior es correcta. Lo he confirmado con el siguiente progtwig:

 #include  int main(){ dup2(0, 7); write(7, "Hey, 1\n", 7); close(0); write(7, "Hey, 2\n", 7); close(7); write(7, "Hey, 3\n", 7); } 

Lo que resulta en la siguiente salida:

 $ gcc dup2Test.c && ./a.out Hey, 1 Hey, 2 

Gracias, Jonathan!