2008-11-19 10 views
7

Comment lancer une application et capturer la sortie via stdout et peut-être stderr? Je suis en train d'écrire un système de construction automatisé et j'ai besoin de capturer la sortie pour analyser. Je voudrais mettre à jour svn repo et saisir le numéro de révision afin que je puisse déplacer les fichiers dans autobuild/revNumber/si réussi. Je voudrais également construire en utilisant make et télécharger le texte de la compilation sur mon serveur pour que tout le monde puisse voir les avertissements et les erreurs sur une version ayant échoué.lancer l'application, capturer stdout et stderr en C++

Je ne trouve pas la fonction system(), mais je trouve la fonction CreateProcess() sur MSDN. Je suis capable de lancer ce dont j'ai besoin mais je ne sais pas comment capturer le stderr et le stdout. Je remarque que le processus se lance séparément sauf si je mets un point d'arrêt et que je garde mon application en cours de sortie, ce qui lui permettra de conserver tout le texte dans la fenêtre de ma console d'application. Je voudrais également attendre jusqu'à ce que tous les processus soient terminés et ensuite scanner les données qu'il a produites pour faire toutes les opérations supplémentaires dont j'ai besoin. Comment puis-je faire ça?

Répondre

11

En coquilles réelles (ce qui signifie, pas des coquilles de mer - je veux dire, pas en C Shell ou ses dérivés), puis:

program arg1 arg2 >/tmp/log.file 2>&1 

Ce programme fonctionne avec les arguments donnés, et redirige stdout/tmp /fichier journal; la notation ( hieroglyph) '2>&1' envoie à la fin stderr (descripteur de fichier 2) à la même place que stdout (descripteur de fichier 1). Notez que la séquence des opérations est importante; Si vous les inversez, alors l'erreur standard ira à l'endroit où va la sortie standard, puis la sortie standard (mais pas l'erreur standard) sera redirigée vers le fichier. Le choix du nom de fichier indiqué est abyssal pour de nombreuses raisons - vous devriez permettre à l'utilisateur de choisir le répertoire, et probablement inclure l'ID du processus ou l'horodatage dans le nom du fichier.

LOG=${TMPDIR:-/tmp}/log.$$.$(date +%Y%m%d-%H%M%S) 
program arg1 arg2 >$LOG 2>&1 

En C++, vous pouvez utiliser la fonction pour exécuter des processus system() (hérité de C). Si vous avez besoin de connaître le nom du fichier dans le programme C++ (plausible), alors générez le nom dans le programme (strftime() est votre ami) et créez la chaîne de commande avec ce nom de fichier. (Strictement, vous devez également getenv() pour obtenir $ TMPDIR, et la fonction POSIX getpid() pour obtenir l'ID du processus, puis vous pouvez simuler le script shell à deux lignes (bien que le PID utilisé soit du programme C++, pas le programme lancé . shell)

vous pourriez plutôt utiliser la fonction POSIX popen(), vous auriez à inclure la notation « 2>&1 » dans la chaîne de commande que vous créez pour envoyer l'erreur standard de la commande au même endroit que la sortie standard va , mais vous n'avez pas besoin d'un fichier temporaire:

Vous pouvez ensuite lire le flux de fichiers. Je ne suis pas sûr s'il y a un méthode propre pour mapper un flux de fichier C dans un flux istream C++; il y a probablement.

+0

Je crois que le nom du "&" caractère/glyphe est l'esperluette. –

+0

D'accord: mais je parlais de '2> & 1' comme du 'hiéroglyphe' (ce qui, je l'admets volontiers, est une mauvaise utilisation du terme). –

+0

Je pense que ce serait un peu plus clair si vous parliez de '2> & 1' comme d'une 'redirection' au lieu d'une 'heiroglyph'. Quelqu'un qui n'est pas familier avec la linguistique égyptienne et va chercher le terme sur Wikipédia pourrait devenir très confus. :) –

4

Vous devez remplir la structure STARTUP_INFO, qui contient hStdInput, hStdOutput et hStdError. N'oubliez pas d'hériter des handles lorsque vous créez 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); 

Je n'ai pas montré les aspects de la gestion des erreurs, ce que vous devrez faire. Le 5ème argument est défini sur true pour hériter des handles. D'autres ont expliqué comment créer des tuyaux, donc je ne vais pas le répéter ici.

0

Les CRT de Microsoft et la bibliothèque MSDN incluent la fonction système et la fonction _popen.

Questions connexes