execv * et écrire dans stdin

J’essaie d’exécuter un programme avec une entrée standard spécifique. Je réussis en utilisant un descripteur de fichier d’un fichier où il y a ce que je veux mettre dans le stdin, mais je n’arrive pas à écrire directement sur le stdin:

$cat input.test echo Hello $ 

Code 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); } 

Ça marche :

 $./a.out Hello $ 

Mais si j’essaye d’écrire directement sur le STDIN en utilisant pipe, le programme n’affiche rien et continue de fonctionner:

 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); } 

Merci de votre aide

Cordialement, Bastien.

EDIT Problème résolu:

Merci pour vos réponses, voici le code qui fonctionne:

 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; } 

Vous devez duper le côté lecture du canal vers stdin , pas le côté écriture. (Et écrivez sur le côté écriture, évidemment.)

 #include  #include  #include  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; } 

Assurez-vous cependant de vérifier les valeurs de retour de toutes ces fonctions, mais vous n’arriverez jamais à déboguer votre code si vous ne le faites pas.

execv et ses amis remplacent le programme en cours par celui spécifié; ils ne reviennent pas – l’exécution se poursuit au début du nouveau programme.

Donc, ce que vous faites normalement, c’est fork et, dans l’une des fourches, appelez execv . Vous lisez et écrivez ensuite dans le tuyau de votre programme en continuant dans l’autre fourchette. Il existe généralement des fonctions popen pour le faire dans la plupart des langues; Malheureusement, dans POSIX, le popen () est ssortingctement lu ou écrit et non bidirectionnel.

Heureusement, j’ai créé, testé et publié une fonction popen3 . Cela vous donne trois descripteurs de fichiers – un pour stdin au processus et deux pour stdout et stderr. Vous pouvez alors utiliser write () sur le stdin.

Lorsque vous appelez pipe, fd [0] est ouvert à la lecture et fd [1] est ouvert à l’écriture. Vous devriez tromper stdin sur le côté lecture (fd [0]) et écrire sur le côté écriture (fd [1]). Vérifiez la valeur de retour de write: c’est probablement -1.

Mais il y a un problème plus important. Vous ne fermez jamais les deux côtés du tuyau. bash peut bloquer une lecture et ne rien faire jusqu’à ce que le côté écriture du canal soit fermé. Vous devriez fermer les deux côtés du tuyau après avoir dupé et écrit. (Ou définissez FD_CLOEXEC).

Notez également que si vous le faites comme vous le faites, vous êtes sortingbutaire de la taille du tampon du tuyau. Si vous écrivez trop, l’écriture sera bloquée car il n’y a pas de lecteur. Faites-le de manière fiable, vous devriez faire un fork (), exécuter exec dans l’enfant et écrire dans le tube du parent. De cette façon, le tube aura un lecteur et vous pourrez y écrire autant de données que vous le souhaitez.