Перенаправление stdout с помощью > и stderr с помощью >> в один файл приводит к отсутствию stderr.

Вопрос или проблема

Я перенаправляю stdout и stderr в один и тот же файл, используя > и >> соответственно:

rsync -a --exclude cache/ src_folder/ target_folder/ 1>out_err.log 2>>out_err.log

Однако ошибка стандартного вывода не записывается в файл. Что происходит с ошибкой стандартного вывода, когда используется >> вместо > для перенаправления обоих в один и тот же файл?

Я собирался записать stdout в новый файл, а затем добавить stderr в тот же файл.

Проблема с использованием 1>out_err.log 2>>out_err.log заключается в том, что это создает два отдельных открытых дескриптора файла для вашего целевого файла: один для stdout и один для stderr. Точный результат в этом случае зависит от порядка, в котором записываются сообщения, так же, как если бы две отдельные команды записывали в этот файл. Если stderr записывает в файл первым, то когда stdout начнет записывать, он сотрет все, что было записано ранее. (Более того, “первым” может не совпадать с тем, что вы увидели бы, если бы выполнили ту же команду в консоли.)

Обычный и безопасный подход в этой ситуации — сначала перенаправить stdout в ваш желаемый файл лога, а затем использовать 2>&1, чтобы перенаправить stderr в тот же открытый дескриптор файла, что и stdout.

rsync -a --exclude cache/ src_folder/ target_folder/ > out_err.log 2>&1

Я собирался записать stdout в новый файл, а затем добавить stderr в тот же файл.

Утилита rsync чередует свой stdout и stderr, поэтому в этой ситуации вам нужно отделить их, сохраняя stderr до тех пор, пока вы не запишите все из stdout. Утилита sponge (из moreutils) позволит вам сделать это.

rsync… 2>&1 >out_err.log | sponge -a out_err.log

Здесь мы записываем stdout напрямую из rsync, передавая stderr во stdin sponge. Этот инструмент принимает все из stdin и ничего не записывает (удерживая все в памяти), пока трубопровод не будет закрыт, после чего все будет добавлено в файл лога.

Ответ или решение

Чтобы корректно перенаправить стандартный вывод (stdout) и стандартный вывод ошибок (stderr) в один и тот же файл, важно понимать, как работает механизм перенаправления в оболочке Unix/Linux.

Ваше текущее решение:

rsync -a --exclude cache/ src_folder/ target_folder/ 1>out_err.log 2>>out_err.log

не дает ожидаемого результата, потому что вы создаете два отдельных дескриптора файлов для одного и того же файла out_err.log. Таким образом, когда stderr и stdout записываются в файл, порядок их записи становится непредсказуемым: какое-то сообщение из stderr может быть перезаписано сообщением из stdout, и наоборот.

Чтобы решить эту проблему, правильнее будет перенаправить stdout в файл, а затем перенаправить stderr на тот же дескриптор файла, что и stdout. Это делается следующим образом:

rsync -a --exclude cache/ src_folder/ target_folder/ > out_err.log 2>&1

Таким образом, вы записываете stdout в out_err.log, а затем перенаправляете stderr (2) в тот же поток, что и stdout (1), что гарантирует, что оба вывода будут записываться в правильном порядке.

Однако, если ваша цель — сначала записать stdout в новый файл, а затем добавить stderr в тот же файл, необходимо использовать другой подход. Поскольку rsync может выводить сообщения как в stdout, так и в stderr, вам следует сохранить stderr, пока не будет завершена запись в stdout.

Для этого вы можете использовать утилиту sponge, которая входит в пакет moreutils. Она позволяет сначала считывать данные из stdin, а записывать их в файл только после закрытия потока. Вот как это можно сделать:

rsync -a --exclude cache/ src_folder/ target_folder/ > >(tee out_err.log) 2>&1 | sponge -a out_err.log

Сначала данные из stdin передаются в tee, который записывает stdout в out_err.log. Затем через | sponge -a out_err.log происходит запуск дополнительного процесса, который будет дожидаться завершения команды и затем добавлять stderr в тот же файл.

Таким образом, описанный вами сценарий будет успешно выполнен, и обе части вывода будут корректно собраны в одном файле.

Оцените материал
Добавить комментарий

Капча загружается...