avvia l'app, acquisisci stdout e stderr in c ++
Domanda
Come posso avviare un'app e acquisire l'output tramite stdout e forse stderr?
Sto scrivendo un sistema di compilazione automatizzato e devo acquisire l'output da analizzare. Vorrei aggiornare il repository svn e afferrare il numero di revisione in modo da poter spostare i file in autobuild / revNumber / in caso di successo. Vorrei anche compilare usando make e caricare il testo di compilazione sul mio server affinché tutti possano vedere gli avvertimenti e gli errori su una build fallita.
Non riesco a trovare la funzione system ()
, ma ho trovato la funzione CreateProcess ()
su MSDN. Sono in grado di lanciare ciò di cui ho bisogno ma non ho idea di come catturare lo stderr e lo stdout. Noto che il processo si avvia separatamente a meno che non imposti un punto di interruzione e mantenga la mia app in uscita, che manterrà quindi tutto il testo nella finestra della mia console dell'app. Vorrei anche aspettare fino al termine di tutti i processi e quindi eseguire la scansione dei dati prodotti per eseguire qualsiasi operazione aggiuntiva di cui ho bisogno. Come posso fare tutto questo?
Soluzione
Nelle conchiglie reali (che significa, non conchiglie di mare - voglio dire, non in C Shell o suoi derivati), quindi:
program arg1 arg2 >/tmp/log.file 2>&1
Esegue il programma con gli argomenti forniti e reindirizza lo stdout su /tmp/log.file; la notazione ( geroglifico ) ' 2 > & amp; 1
' alla fine invia stderr (descrittore di file 2) nello stesso posto in cui sta andando stdout (descrittore di file 1). Si noti che la sequenza delle operazioni è importante; se li invertite, l'errore standard andrà a destinazione dell'output standard e quindi l'output standard (ma non l'errore standard) verrà reindirizzato al file.
La scelta del nome del file mostrato è terribile per numerosi motivi: dovresti consentire all'utente di scegliere la directory e probabilmente includere l'ID del processo o il timestamp nel nome del file.
LOG=${TMPDIR:-/tmp}/log.$.$(date +%Y%m%d-%H%M%S)
program arg1 arg2 >$LOG 2>&1
In C ++, è possibile utilizzare la funzione system ()
(ereditata da C) per eseguire i processi. Se devi conoscere il nome del file nel programma C ++ (plausibile), quindi genera il nome nel programma ( strftime ()
è tuo amico) e crea la stringa di comando con quel nome file.
(Rigorosamente, è necessario anche getenv ()
per ottenere $ TMPDIR e la funzione POSIX getpid ()
per ottenere l'ID processo, quindi è possibile simulare la doppia riga script di shell (anche se il PID usato sarebbe del programma C ++, non della shell avviata).
È possibile invece utilizzare la funzione POSIX popen ()
; dovresti includere la notazione ' 2 > & amp; 1
' nella stringa di comando che crei per inviare l'errore standard del comando nella stessa posizione dell'output standard, ma non è necessario un file temporaneo:
FILE *pp = popen("program arg1 arg2 2>&1", "r");
È quindi possibile leggere il flusso di file. Non sono sicuro che esista un modo semplice per mappare un flusso di file C in un istream C ++; probabilmente c'è.
Altri suggerimenti
Devi riempire la struttura STARTUP_INFO, che ha hStdInput, hStdOutput e hStdError. Ricorda di ereditare gli handle quando CreateProcess.
/* Assume you open a file handle or pipe called myoutput */
STARTUP_INFO si_startinfo;
ZeroMemory(&si_startinfo, sizeof(STARTUP_INFO));
si_startinfo.cb = sizeof(STARTUP_INFO);
si_startinfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
si_startinfo.hStdOutput = myoutput;
si_startinfo.hStdError = myoutput;
si_startifno.dwFlags != STARTF_USEHANDLES;
PROCESS_INFORMATION pi_procinfo;
ZeroMemory(&pi_procinfo, sizeof(PROCESS_INFORMATION);
CreateProcess(NULL, cmdline, NULL, NULL, true, 0, NULL, pathname, &si_startinfo, &pi_procinfo);
Non ho mostrato gli aspetti di gestione degli errori, che dovrai fare. Il quinto argomento è impostato su true per ereditare gli handle. Altri hanno spiegato come creare pipe in modo che non lo ripeterò qui.
I CRT di Microsoft e la libreria MSDN includono la funzione di sistema e la funzione _popen.