запуск приложения, захватить stdout и stderr в C++

Как запустить приложение и захватить вывод через stdout и, возможно, stderr?

Я пишу автоматизированную систему сборки, и мне нужно захватить вывод для анализа. Я хотел бы обновить РЕПО svn и захватить номер редакции, чтобы я мог переместить файлы в autobuild/revNumber/ в случае успеха. Я также хотел бы построить с помощью make и загрузить текст компиляции на мой сервер, чтобы все видели предупреждения и ошибки при неудачной сборке.

Я не могу найти system() функция, но я нашел CreateProcess() функция на MSDN. Я могу запустить то, что мне нужно, но я понятия не имею, как захватить stderr и stdout. Я замечаю, что процесс запускается отдельно, если я не установлю точку останова и не сохраню свое приложение, которое затем сохранит весь текст в окне консоли приложения. Я также хотел бы дождаться завершения всех процессов, а затем Сканировать полученные данные для выполнения любых дополнительных операций. Как мне это сделать?

3 ответов


в реальных раковинах (то есть, не в морских раковинах-я имею в виду, не в раковине C или ее производных), то:

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

это запускает программу с заданными аргументами и перенаправляет stdout в /tmp/log.файл; обозначение (иероглиф) '2>&1 ' В конце отправляет stderr (файловый дескриптор 2) в то же место, что и stdout (файловый дескриптор 1). Обратите внимание, что важна последовательность операций; если вы их отмените, то стандартная ошибка перейдет туда, где стандартная вывод шел, а затем стандартный вывод (но не стандартная ошибка) будет перенаправлен в файл.

выбор показанного имени файла ужасен по многим причинам - вы должны позволить пользователю выбрать каталог и, вероятно, должны включить идентификатор процесса или отметку времени в имя файла.

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

в C++, вы можете использовать system() функция (наследуется от C) для запуска процессов. Если вам нужно знать имя файла в программе C++ (правдоподобно), то создайте имя в программе (strftime() ваш друг) и создайте командную строку с этим именем файла. (Строго говоря, вам также нужно getenv() чтобы получить $TMPDIR и функцию POSIX getpid() чтобы получить идентификатор процесса, а затем вы можете смоделировать двухстрочный сценарий оболочки (хотя используемый PID будет программой C++, а не запущенной оболочкой).

вместо этого вы можете использовать POSIX popen() функция; вы должны были бы включить '2>&1' нотация в командной строке, которую вы создаете для отправки Стандартная ошибка команды в том же месте, что и стандартный вывод, но вам не понадобится временный файл:

FILE *pp = popen("program arg1 arg2 2>&1", "r");

затем вы можете прочитать поток файлов. Я не уверен, есть ли чистый способ отобразить поток файлов C в поток c++; вероятно, есть.


вам нужно заполнить структуру STARTUP_INFO, которая имеет hStdInput, hStdOutput и hStdError. Не забудьте наследовать дескрипторы при 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);

Я не показал аспекты обработки ошибок, которые вам нужно будет сделать. 5-й аргумент имеет значение true для наследования дескрипторов. Другие объяснили, как создавать трубы, поэтому я не буду повторять это здесь.


CRTs Microsoft и библиотека MSDN включают системную функцию и функцию _popen.