2

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

Мотивация: у меня есть команда в моем crontab, и я хочу записать весь ее вывод в файл, и я хочу, чтобы cron отправил мне электронное письмо, если что-то будет записано в вывод ошибки.

У меня был некоторый успех с этим:

(echo out1; echo err1 1>&2; echo out2; echo err2 1>&2) \
    2> >(tee -a log) \
    1>>log

Или же:

(echo err1 1>&2; echo out2; echo err2 1>&2) \
    3>&1 \
    1> >(tee -a log 1>/dev/null) \
    2> >(tee -a log 1>&3)

Или с exec:

exec 3>&1
exec 1> >(tee -a log2 1>/dev/null)
exec 2> >(tee -a log2 1>&3)
echo out1; echo err1 1>&2; echo out2; echo err2 1>&2

(Третье решение также регистрирует приглашение, поэтому оно не работает в интерактивной оболочке.)

Проблема всех трех решений состоит в том, что файл журнала содержит строки в другом порядке:

out1
out2
err1
err2

Вместо этого:

out1
err1
out2
err2

Есть ли способ предотвратить это? Нечто подобное 2>&1 , которое дублирует сам вывод, а не дескриптор.

Есть очень похожий вопрос для Windows

1 ответ1

0

Я думаю, вы хотите максимально упростить и оптимизировать это. Сейчас я не могу придумать лучшего решения, чем шаг за шагом. А именно,

$ echo out1 >> log
$ echo err1 | tee -a log >&2
err1
$ echo out2 >> log
$ echo err2 | tee -a log >&2
err2
$ cat log
out1
err1
out2
err2

Ну, вы можете использовать сопроцесс, чтобы вам не приходилось много раз звонить, если это важно для вас.

$ coproc tee -a log
[1] 26417
$ echo out1 >> log
$ echo err1 >&"${COPROC[1]}"
$ echo out2 >> log
$ echo err2 >&"${COPROC[1]}"
$ cat log
out1
err1
out2
err2

Теперь, какие бы ошибки не были, они ждут в выходном канале сопроцесса. Если вам просто нужно проверить, есть ли что-то там, это будет делать:

$ timeout 1 head -n1 <&"${COPROC[0]}" >/dev/null && echo yes # or something else
yes

Если вы хотите повторно использовать ошибки, вы можете изменить сопроцесс в соответствии с вашими целями.

Вы также можете установить перенаправление для скриптов и двоичных файлов. Конечно, до тех пор, пока они сами не имеют жестко перенаправленных перенаправлений. Таким образом, вы можете сделать это,

$ some_executable 2>&"${COPROC[1]}" >>log

И логика остается прежней.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .