Вопрос или проблема
Я перенаправляю 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 в памяти и не записывает их в файл до закрытия входного потока, что позволяет гарантировать, что ошибки сохранятся после завершения записи стандартного вывода.
Таким образом, с помощью этого подхода вы предотвратите возможные проблемы с потерей данных при записи в один и тот же файл.