2013-02-25 9 views
12

Sto scrivendo un programma in C++ che esegue e le uscite (in tempo reale), uno script di shell, makefile o semplicemente un altro programma. Tuttavia mi piacerebbe avere il mio programma di ritorno in modo diverso quando ci sono errori o errori.Come catturare l'exit_code e stderr del comando eseguito in C++?

#include "execxi.h" 



using namespace std; 


int execXI::run(string command) 
{ 

    FILE *in; 
    char buff[512]; 
    // is this the check for command execution exited with not 0? 
    if(!(in = popen(command.c_str(), "r"))){ 
      // I want to return the exit code and error message too if any 
     return 1; 
    } 
    // this part echoes the output of the command that's executed 
    while(fgets(buff, sizeof(buff), in)!=NULL){ 
     cout << buff; 
    } 
    pclose(in); 
    return 0; 



} 

è quello che ho finora.

Diciamo che questo script corse make per costruire un programma e ha dato un errore in questo modo

on_target_webkit_version out/Release/obj/gen/webkit_version.h 
Traceback (most recent call last): 
    File "../build/webkit_version.py", line 107, in <module> 
    sys.exit(main()) 
    File "../build/webkit_version.py", line 103, in main 
    return EmitVersionHeader(*sys.argv[1:]) 
    File "../build/webkit_version.py", line 86, in EmitVersionHeader 
    webkit_revision = GetWebKitRevision(webkit_dir, version_file) 
    File "../build/webkit_version.py", line 60, in GetWebKitRevision 
    version_info = lastchange.FetchVersionInfo(
AttributeError: 'module' object has no attribute 'FetchVersionInfo' 
make: *** [out/Release/obj/gen/webkit_version.h] Error 1 
  • E 'possibile per me sapere che questo è uscito con l'errore?

    • fa che uscire con il codice di else than 0 in quanto si tratta di un errore?

    • È che l'ultima parte è uscita nei stderr?

Considerando che make terminato con il codice non 0, diciamo 1, ed è uscita in stderr non è forse possibile per me catturare questi codici di uscita e il messaggio di errore, alla fine?

Come posso catturare il codice di uscita e stderr dopo emettere i risultati del programma, e restituire il exit code/stderr nella funzione?

+3

pclose restituisce uno stato di uscita. –

+0

http://jineshkj.wordpress.com/2006/12/22/how-to-capture-stdin-stdout-and-stderr-of-child-program/ –

risposta

13

Se siete interessati al codice di errore, questo è un modo più portabile di ottenerlo piuttosto che dividendo per 256:

printf("Exit code: %i\n", WEXITSTATUS(pclose(fp))); 

Tuttavia, popen è un modo, quindi o si è creare ulteriori soluzioni alternative per il solito stile di reindirizzamento in guscio, o si segue questo codice non testato per farlo bene:

#include <unistd.h> 
#include <stdio.h> 

/* since pipes are unidirectional, we need two pipes. 
    one for data to flow from parent's stdout to child's 
    stdin and the other for child's stdout to flow to 
    parent's stdin */ 

#define NUM_PIPES   2 

#define PARENT_WRITE_PIPE 0 
#define PARENT_READ_PIPE 1 

int pipes[NUM_PIPES][2]; 

/* always in a pipe[], pipe[0] is for read and 
    pipe[1] is for write */ 
#define READ_FD 0 
#define WRITE_FD 1 

#define PARENT_READ_FD (pipes[PARENT_READ_PIPE][READ_FD] ) 
#define PARENT_WRITE_FD (pipes[PARENT_WRITE_PIPE][WRITE_FD]) 

#define CHILD_READ_FD (pipes[PARENT_WRITE_PIPE][READ_FD] ) 
#define CHILD_WRITE_FD (pipes[PARENT_READ_PIPE][WRITE_FD] ) 

void 
main() 
{ 
    int outfd[2]; 
    int infd[2]; 

    // pipes for parent to write and read 
    pipe(pipes[PARENT_READ_PIPE]); 
    pipe(pipes[PARENT_WRITE_PIPE]); 

    if(!fork()) { 
     char *argv[]={ "/usr/bin/bc", "-q", 0}; 

     dup2(CHILD_READ_FD, STDIN_FILENO); 
     dup2(CHILD_WRITE_FD, STDOUT_FILENO); 

     /* Close fds not required by child. Also, we don't 
      want the exec'ed program to know these existed */ 
     close(CHILD_READ_FD); 
     close(CHILD_WRITE_FD); 
     close(PARENT_READ_FD); 
     close(PARENT_WRITE_FD); 

     execv(argv[0], argv); 
    } else { 
     char buffer[100]; 
     int count; 

     /* close fds not required by parent */  
     close(CHILD_READ_FD); 
     close(CHILD_WRITE_FD); 

     // Write to child’s stdin 
     write(PARENT_WRITE_FD, "2^32\n", 5); 

     // Read from child’s stdout 
     count = read(PARENT_READ_FD, buffer, sizeof(buffer)-1); 
     if (count >= 0) { 
      buffer[count] = 0; 
      printf("%s", buffer); 
     } else { 
      printf("IO Error\n"); 
     } 
    } 
} 

Il codice è da qui:

http://jineshkj.wordpress.com/2006/12/22/how-to-capture-stdin-stdout-and-stderr-of-child-program/

+1

Per me, usare 'WEXITSTATUS' con' pclose() 'restituisce' 1' per avere successo e '-1' per non aver avuto successo. Suona bene o ho fatto qualcosa di sbagliato? –

+0

@ AndyJ0076: mi sta bene. – lpapp

+0

c'è una spiegazione https://groups.google.com/forum/#!topic/utah-c/g4MpZVnJ7es riguardante diversi codici di uscita non 0 –

9

Il valore di ritorno del processo figlio è nella parte superiore 8 bit. Bisogna dividere il valore restituito di pclose per 256, allora si ottiene il valore di ritorno ricercato del processo figlio.

ottenuto da http://bytes.com/topic/c/answers/131694-pclose-returning-termination-status-command

la mia risposta sarebbe pclose(in)/256 è il codice di uscita.

io ancora non so come catturare stderr o sdtout diverso, ma fino a quando c'è una risposta per questo voglio accettare questo come la mia risposta.

+0

Lo stesso problema qui. Hai trovato una soluzione alla tua domanda aperta? La mia soluzione sarebbe quella di convogliare lo stderr in un file e di leggerlo di nuovo con una chiamata popen. – Strubbl

+1

@Strubbl Tipo di ... controlla questo https://github.com/aponxi/npm-execxi/blob/master/execxi.cpp Ho scritto un'estensione C++ per nodejs per eseguire comandi di shell. Penso di non aver implementato la divisione di stderr e stdout perché non tutti i programmi usati stderr per errori è quello che ho capito. E credo che mi sia venuto in mente qualcosa per evitare che il tipo di approccio di "file scrive più che letto". Spero che la lettura di ciò che ho fatto in quel codice sia d'aiuto (è stato un po 'così sono confuso nei dettagli.) – Logan

+1

Puoi anche usare il reindirizzamento della shell, 2> & 1, e cercare i messaggi di errore. – ChuckCottrill

0

Grazie per la risposta di codice di uscita Logan.

Credo che una di andata e ritorno per ottenere stderr sarebbe quello di reindirizzare in un file temporaneo:

FILE* f = popen("cmd 2>/tmp/tmpfile.txt", "r"); 
+1

Crea un file di output univoco (magari usando pid), in modo che quando hai bisogno di eseguire 2 o più copie, ottieni un output utile. – ChuckCottrill

+0

Usa 'tempnam',' tmpfile' o 'tmpnam' per creare file temporarty, ** mai ** hardcode i nomi. – rsp

Problemi correlati