2011-11-11 15 views
6

Estoy intentando ejecutar un programa con una entrada estándar específica. Tengo éxito mediante el uso de un descriptor de archivo de un archivo donde no es lo que quiero para poner en la entrada estándar, pero no llego a escribir directamente en la entrada estándar:execv * y escriba en stdin

$cat input.test 
echo Hello 
$ 

Código C:

int main(int argc, char **argv) 
{ 
    int fd = 0; 

    fd = open("input.test", O_CREAT); 
    close(STDIN_FILENO); 
    dup2(fd, STDIN_FILENO); 
    char *const args[] = { "bash", NULL }; 
    execvp("bash", args); 
} 

Eso funciona:

$./a.out 
Hello 
$ 

Pero si trato de escribir directamente en la tubería STDIN usando el programa muestra nada y sigue funcionando:

int main(int argc, char **argv) 
{ 
    int fds[2]; 

    pipe(fds); 
    close(STDIN_FILENO); 
    dup2(fds[1], STDIN_FILENO); 
    write(fds[1], "echo Hello;", 11); // Résults are identics with fds[0] 
    char *const args[] = { "bash", NULL }; 
    execvp("bash", args); 
} 

Gracias por su ayuda

Cordialmente, Bastien. Problema

EDITAR resuelto:

Gracias por sus respuestas, aquí el código que funciona:

int main(void) 
{ 
    int fd[2]; 
    pid_t pid; 

    if (pipe(fd) < 0) 
     return EXIT_FAILURE; 

    if ((pid = fork()) < 0) 
     return EXIT_FAILURE; 
    else if (pid != 0) { /* father */ 
     close(fd[1]); 
     dup2(fd[0], STDIN_FILENO); 
     execlp("bash", "bash", (char *)0); 
    } else { /* son */ 
     close(fd[0]); 
     write(fd[1], "echo hello\n", 11); 
    } 

    return EXIT_SUCCESS; 
} 

Respuesta

4

Necesita duplicar el lado de lectura de la tubería en stdin, no en el lado de escritura. (Y escribir en el lado de escritura, obviamente.)

#include <unistd.h> 
#include <string.h> 
#include <stdio.h> 
int main(int argc, char **argv) 
{ 
    int fds[2]; 
    char cmd[] = "echo hello\nexit\n"; 

    pipe(fds); 
    close(STDIN_FILENO); 
    dup2(fds[0], STDIN_FILENO); 
    write(fds[1], cmd, strlen(cmd)); 
    char *const args[] = { "bash", NULL }; 
    execvp("bash", args); 
    return 0; 
} 

asegúrese de comprobar los valores de retorno de todas aquellas funciones embargo, nunca se las arreglan para depurar el código si no lo hace.

+0

¿por qué están invalidando a los demás?las mentes inquisitivas quieren saber :) – Will

+0

No tengo idea de por qué todas las respuestas fueron downvoted. – Mat

2

Cuando se llama a la tubería, fd [0] está abierto para lectura, y fd [1] es abierto para escribir Debería estar duplicando stdin en el lado de lectura (fd [0]) y escribiendo en el lado de escritura (fd [1]). Compruebe el valor de retorno de la escritura: probablemente sea -1.

Pero hay un problema mayor. Nunca cierras a ambos lados de la tubería. bash puede bloquear en una lectura y nunca hacer nada hasta que se cierre el lado de escritura de la tubería. Debería cerrar ambos lados de la tubería después de duplicar y escribir. (O configure FD_CLOEXEC).

3

execv y sus amigos reemplazan el programa en ejecución actual con el especificado; no regresan - la ejecución continúa en el inicio del nuevo programa.

Lo que normalmente hace es fork y, en una de las horquillas, llame al execv. A continuación, lee y escribe a través del conducto de su programa y continúa en el otro tenedor. Generalmente hay popen funciones para hacer esto en la mayoría de los idiomas; lamentablemente en POSIX el popen() es estrictamente de lectura o escritura y no bidireccional.

Afortunadamente, tengo made, tested and published a popen3 función. Esto le devuelve tres descriptores de archivos: uno para stdin al proceso y dos para stdout y stderr. Puede usar write() en el stdin.

0

También tenga en cuenta que al hacerlo de la manera en que lo hace, depende del tamaño del búfer de la tubería. Si escribe demasiado, se bloqueará la escritura ya que no hay lector. Hazlo de manera confiable, debes fork(), ejecutar en el niño y escribir en la tubería en el padre. De esta forma, la tubería tendrá un lector y podrá escribir tantos datos como desee en ella.