запуск приложения, захватить 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 для наследования дескрипторов. Другие объяснили, как создавать трубы, поэтому я не буду повторять это здесь.