запустить приложение, захватить stdout и stderr в c ++ - PullRequest
7 голосов
/ 19 ноября 2008

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

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

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

Ответы [ 3 ]

11 голосов
/ 19 ноября 2008

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

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

Это запускает программу с заданными аргументами и перенаправляет стандартный вывод в /tmp/log.file; запись ( иероглиф ) '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 в istream C ++; там, вероятно, есть.

4 голосов
/ 19 ноября 2008

Вам необходимо заполнить структуру STARTUP_INFO, которая имеет hStdInput, hStdOutput и hStdError. Не забудьте наследовать дескрипторы, когда вы создаете процесс.

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

0 голосов
/ 19 ноября 2008

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

...