Дублирование вывода stderr и объединение со stderr в bash без изменения порядка

353
TPE

Я хочу записать как 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

2
Дубликат на U & L: https://unix.stackexchange.com/questions/79996/how-to-redirect-stdout-and-stderr-to-a-file-and-display-stderr-to-console. Tomasz 6 лет назад 0
Да, извините, я не нашел это. Я не могу пометить вопрос как дубликат, потому что другой вопрос относится к другому домену, что мне делать? Кстати, для меня несколько удивительно, что нет чистого решения для чего-то подобного TPE 6 лет назад 0
Вы не опубликовали это, так что это не перекрестная публикация. Не беспокойся тогда. Просто оставь все как есть. Что касается рассматриваемого вопроса, это не так удивительно, как может показаться. Это простота STDERR и STDOUT - два разных канала, и их синхронизация привела бы к затратам. Вы можете подумать о том, как избежать их синхронизации или проверки в общем журнале признаков ошибки с помощью `grep` или чего-то подобного. Tomasz 6 лет назад 0

1 ответ на вопрос

0
Tomasz

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

$ 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 >&"$" $ echo out2 >> log $ echo err2 >&"$" $ cat log out1 err1 out2 err2 

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

$ timeout 1 head -n1 <&"$" >/dev/null && echo yes # or something else yes 

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

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

$ some_executable 2>&"$" >>log 

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

Это работает и это легко сделать, но команды echo являются лишь примерами, я хочу использовать перенаправление с установленными сторонними скриптами и двоичными файлами, их было бы довольно громоздко модифицировать таким образом. Я не знал `coproc`, он делает код приятнее, но, похоже, не решает проблему, описанную выше. TPE 6 лет назад 0
@TPE Это не имеет значения. Я приложил объяснение. Tomasz 6 лет назад 0
'' Вы также можете установить перенаправление для скриптов и двоичных файлов '' Я не думаю, что это работает, если исполняемый файл выполняет запись в stdout и stderr в определенном порядке, они все равно перепутаны. TPE 6 лет назад 0
@TPE Вы пробовали это? Tomasz 6 лет назад 0
Да, я скопировал команды echo в скрипт `.sh`, а также попробовал простую программу на C с такими выводами:` write (2, "err1 \ n", 5); ` TPE 6 лет назад 0
@TPE Хорошо. Тогда это не так просто. https://unix.stackexchange.com/questions/79996/how-to-redirect-stdout-and-stderr-to-a-file-and-display-stderr-to-console Tomasz 6 лет назад 0

Похожие вопросы