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

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

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

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

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

Я намеревался записать 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 и не записывает ничего (удерживая всё в памяти) до тех пор, пока канал не будет закрыт; в этот момент всё добавляется в файл журнала.

(Заметка о порядке 2>&1 >out_err.log. Изначально файловый дескриптор #1 (stdout) утилиты rsync подключен к каналу |. Затем мы начинаем перенаправлять файловые дескрипторы. Сначала 2>&1 дублирует файловый дескриптор #1 для stdout в fd #2 (stderr), также подключая его к каналу. Затем мы перенаправляем fd #1 (stdout) в выходной файл. Теперь stderr (по-прежнему) подключен к каналу, поэтому ошибки будут передаваться через него в sponge.)

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

Ваш вопрос касается перенаправления стандартного вывода (stdout) и стандартного потока ошибок (stderr) в один и тот же файл, и о том, почему при использовании операторов > и >> для этих целей возникает проблема.

Когда вы выполняете команду следующим образом:

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

Вы создаете два разных открытых файловых дескриптора для одного и того же файла out_err.log: один для stdout и другой для stderr. Это может привести к ситуации, когда другая часть вывода перезаписывает ранее записанное содержимое файла. Если stderr записывает данные раньше, чем stdout, последние записи stderr могут быть потеряны при записи stdout.

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

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

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

Если вам надо записать stdout и сохранить stderr до завершения записи stdout, и затем добавить stderr в тот же файл, вы можете использовать утилиту sponge из пакета moreutils. Вот как это можно сделать:

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

В этом примере stdout будет записываться прямо из команды rsync, в то время как stderr будет перенаправлен в стандартный ввод sponge. Эта утилита позволяет накапливать данные из stdin в памяти и не записывает их в файл до закрытия входного потока, что позволяет гарантировать, что ошибки сохранятся после завершения записи стандартного вывода.

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

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

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