C: как перенаправить stderr из системной команды в стандартный вывод или файл?
Команда оболочки $ avrdude -c usbtiny
выводит текст в stderr. Я не могу прочитать его с помощью таких команд, как head-less-more, потому что это не стандартный вывод. Я хочу, чтобы текст на стандартный вывод или в файл. Как я могу сделать это в C? Я попытался решить проблему с помощью моего последнего вопроса, но все еще не решен.
4 ответа
Я не пробовал что-то подобное в OpenBSD, но по крайней мере в некоторых *nix-подобных системах вы можете сделать это, используя dup2
,
#include <unistd.h>
#include <stdio.h>
int main(void) {
fprintf(stderr, "This goes to stderr\n");
dup2(1, 2); //redirects stderr to stdout below this line.
fprintf(stderr, "This goes to stdout\n");
}
Нормальный способ будет что-то вроде:
avrdude -c usbtiny 2>&1
Это направляет то, что обычно идет в stderr, вместо этого в stdout. Если вы предпочитаете направить его в файл, вы можете сделать что-то вроде:
avrdude -c usbtiny 2> outputfile.txt
Далее используется функция POSIX для дублирования стандартного номера выходного файла в стандартный номер файла ошибок. Дублирование stderr в stdout приведено на странице POSIX для dup2
В качестве примера использования функции.
#include <unistd.h>
#include <stdio.h>
int main (void)
{
pid_t child = fork();
if (child == 0)
{
dup2(STDOUT_FILENO, STDERR_FILENO);
execlp("avrdude", "-c", "usbtiny", NULL);
}
else if (child > 0)
{
waitpid(child);
puts("Done!");
}
else
{
puts("Error in forking :(");
}
return 0;
}
Мне нужно как-то заблокировать команду в C, чтобы я мог получить ее stderr
Начните с чтения man fork
, man exec
о том, как запустить дочерний процесс. Заглянуть в man 7 signal
, man sigaction
а также man wait
о том, как пожать ребенка.
Наконец, man dup2
,
Непроверенный код для примера:
int pip_stderr[2];
int r;
int pid;
r = pipe(pip_stderr);
assert( r != -1 );
int pid = fork();
assert( pid != -1 );
if (pid == 0) { /* child */
/* child doesn't need to read from stderr */
r = close(pip_stderr[0]); assert( r != -1 );
/* make fd 2 to be the writing end of the pipe */
r = dup2(pip_stderr[1], 2); assert( r != -1 );
/* close the now redundant writing end of the pipe */
r = close(pip_stderr[1]); assert( r != -1 );
/* fire! */
exec( /* whatever */ );
assert( !"exec failed!" );
} else { /* parent */
/* must: close writing end of the pipe */
r = close( pip_stderr[1] ); assert( r != -1 );
/* here read from the pip_stderr[0] */
r = waitpid(pid,0,0); assert( r == pid );
}
Используя dup2(), мы заменяем stderr (который является fd 2) дочернего элемента записывающим концом канала. pipe () вызывается перед fork(). После разветвления мы также должны закрыть все концы канала, чтобы чтение в родительском процессе фактически получило EOF.
Возможно, есть более простое решение с использованием stdio, но я не знаю об этом. Поскольку popen () запускает команду через оболочку, возможно, можно сказать ей перенаправить stderr в stdout (и отправить stdout в /dev/null). Никогда не пробовал это.
Можно также использовать mktemp () (man 3 mktemp
), чтобы создать имя временного файла, составьте команду для system (), чтобы перенаправить stderr команды во временный файл, и после того, как system () вернет прочитанный временный файл.