Запишите STDOUT & STDERR в файл журнала, также запишите STDERR на экран - PullRequest
14 голосов
/ 20 мая 2010

Я хотел бы запустить несколько команд и записать весь вывод в файл журнала. Я также хочу напечатать любые ошибки на экране (или при желании отправить вывод кому-либо).

Вот пример. Следующая команда запустит три команды и запишет все выходные данные (STDOUT и STDERR) в один файл журнала.

{ command1 && command2 && command3 ; } > logfile.log 2>&1

Вот что я хочу сделать с выводом этих команд:

  • STDERR и STDOUT для всех команд отправляются в лог-файл, на случай, если он понадобится мне позже - обычно я не заглядываю сюда, если нет проблем.
  • Вывести STDERR на экран (или, при необходимости, передать в / bin / mail), чтобы любая ошибка выделялась и не игнорировалась.
  • Было бы неплохо, если бы коды возврата оставались пригодными для использования, чтобы я мог выполнить некоторую обработку ошибок. Может быть, я хочу отправить электронное письмо, если произошла ошибка, например:

    {command1 && command2 && command3; }> logfile.log 2> & 1 || mailx -s "Произошла ошибка" stefanl@example.org

Проблема, с которой я сталкиваюсь, заключается в том, что STDERR теряет контекст во время перенаправления ввода / вывода. '2> & 1' преобразует STDERR в STDOUT, и поэтому я не могу просматривать ошибки, если я делаю 2> error.log

Вот пара сочных примеров. Давайте представим, что я выполняю некоторые знакомые команды сборки, но я не хочу, чтобы вся сборка была остановлена ​​только из-за одной ошибки, поэтому я использую флаг --keep-going.

{ ./configure && make --keep-going && make install ; } > build.log 2>&1

Или вот простой (и, возможно, небрежный) скрипт сборки и развертывания, который будет продолжать работать в случае ошибки.

{ ./configure && make --keep-going && make install && rsync -av --keep-going /foo devhost:/foo} > build-and-deploy.log 2>&1

Я думаю, что мне нужно что-то вроде Bash I / O Redirection , но я не могу понять это.

Ответы [ 5 ]

16 голосов
/ 20 мая 2010
(./doit >> log) 2>&1 | tee -a log

Это займет стандартный вывод и добавит его в файл журнала.

Затем stderr преобразуется в стандартный вывод, который передается по каналу tee, который добавляет его в журнал (если у вас Bash 4, вы можете заменить 2>&1 | на |&) и отправляет его в стандартный вывод либо появляются на tty, либо могут быть переданы другой команде.

Я использовал режим добавления для обоих, чтобы независимо от порядка перенаправления оболочки и tee открытия файла, вы не сдували оригинал. Тем не менее, возможно, что stderr / stdout чередуется неожиданным образом.

1 голос
/ 01 августа 2013

Здесь показано, как выполнить одну или несколько команд, захватив стандартный вывод и ошибку, в том порядке, в котором они были сгенерированы , в лог-файл и отображая только стандартную ошибку на любом экране терминала, который вы лайк. Работает в Bash на Linux. Вероятно, работает в большинстве других сред. Я буду использовать пример, чтобы показать, как это делается.

Отборочные:

Открыть два окна (оболочки, сеансы tmux, что угодно)

Я продемонстрирую некоторые тестовые файлы, поэтому создайте тестовые файлы:

touch /tmp/foo /tmp/foo1 /tmp/foo2

в окне1:

mkfifo /tmp/fifo

0</tmp/fifo cat - >/tmp/logfile

Затем в окне 2:

(ls -l /tmp/foo /tmp/nofile /tmp/foo1 /tmp/nofile /tmp/nofile; echo successful test; ls /tmp/nofile1111) 2>&1 1>/tmp/fifo | tee /tmp/fifo 1>/dev/pts/2

Где вы заменяете /dev/pts/2 на тот, который вы хотите, чтобы выводил stderr.

Причиной различных успешных и неудачных команд в подоболочке является просто создание смешанного потока выходных сообщений и сообщений об ошибках, чтобы вы могли проверить правильность упорядочения в файле журнала. Как только вы поймете, как это работает, замените команды «ls» и «echo» скриптами или командами на ваш выбор.

При использовании этого метода порядок вывода и ошибки сохраняется, синтаксис прост и понятен, и имеется только одна ссылка на выходной файл. Плюс гибкость в размещении дополнительной копии stderr, где вы хотите.

1 голос
/ 20 мая 2010

Если в вашей системе есть узлы / dev / fd / *, вы можете сделать это следующим образом:

( exec 5>logfile.txt ; { command1 && command2 && command3 ;} 2>&1 >&5 | tee /dev/fd/5 )

Это открывает дескриптор файла 5 в ваш лог-файл. Выполняет команды со стандартной ошибкой, направленные на стандартный выход, стандартный выход - на fd 5, а канал stdout (который теперь содержит только stderr) - на тройник, который дублирует вывод на fd 5, который является файлом журнала.

0 голосов
/ 08 апреля 2014

добавить это в начале вашего скрипта

#!/bin/bash
set -e 
outfile=logfile

exec > >(cat >> $outfile)
exec 2> >(tee -a $outfile >&2)

# write your code here

STDOUT и STDERR будут записаны в $outfile, только STDERR будет отображаться на консоли

0 голосов
/ 20 мая 2010

Попробуйте:

command 2>&1 | tee output.txt

Кроме того, вы можете направить stdout и stderr в разные места:

command > stdout.txt >& stderr.txt

command > stdout.txt |& program_for_stderr

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...