2011-11-11 18 views
6

Sto provando a eseguire un programma con uno specifico input standard. Riesco utilizzando un file di descrizione di un file in cui v'è quello che voglio mettere in stdin, ma non riesco a scrivere direttamente sullo standard input:execv * e scrivere in stdin

$cat input.test 
echo Hello 
$ 

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

Quello funziona:

$./a.out 
Hello 
$ 

Ma se provo a scrivere direttamente sullo STDIN utilizzando pipe il programma visualizza nulla e mantiene in esecuzione:

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

Grazie per il vostro aiuto

Cordialmente, Bastien.

EDIT Problema risolto:

Grazie per le vostre risposte, ecco il codice che funziona:

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

risposta

4

È necessario duplicare il lato di lettura del tubo per stdin, non il lato di scrittura. (E scrivere la parte di scrittura, ovviamente.)

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

assicuratevi di controllare i valori di ritorno di tutte quelle funzioni, però, non sarai mai riesce a eseguire il debug del codice, se non lo fai.

+0

perché stai facendo downvoting agli altri?menti curiose vogliono sapere :) – Will

+0

Non ho idea del perché tutte le risposte siano state downvoted. – Mat

2

Quando si chiama pipe, FD [0] è aperto per la lettura, e fd [1] è aperto per la scrittura. Dovresti duplicare lo stdin sul lato di lettura (fd [0]) e scrivere sul lato di scrittura (fd [1]). Controlla il valore di ritorno di write: probabilmente è -1.

Ma c'è un problema più grande. Non si chiude mai alcun lato del tubo. bash potrebbe bloccare una lettura e non fare mai nulla finché il lato di scrittura della pipe non viene chiuso. Dovresti chiudere entrambi i lati della pipa dopo aver duplicato e scritto. (O imposta FD_CLOEXEC).

3

execv e gli amici sostituiscono il programma in corso con quello specificato; non ritornano - l'esecuzione continua invece all'inizio del nuovo programma.

Quindi quello che si fa normalmente è fork e, in una delle forcelle, chiamare execv. Quindi leggi e scrivi attraverso il pipe dal tuo programma che continua nell'altro fork. Di solito ci sono le funzioni popen nella maggior parte delle lingue; purtroppo in POSIX il popen() è rigorosamente letto o scritto e non bidirezionale.

Per fortuna, ho made, tested and published a popen3 funzione. Questo ti restituisce tre descrittori di file: uno per stdin al processo e due per stdout e stderr. È quindi possibile utilizzare write() sullo stdin.

0

Si noti inoltre che, in questo modo, si dipende dalla dimensione del buffer della pipa. Se scrivi troppo, la scrittura verrà bloccata perché non c'è un lettore. Fallo in modo affidabile, dovresti fork(), eseguire exec nel child e scrivere nella pipe nel parent. In questo modo la pipa avrà un lettore e sarai in grado di scrivere quanti più dati desideri.