Как перенаправить stderr в файл

При использовании команды nohup для запуска команды в фоновом режиме часть содержимого отображается в терминале.

cp: error reading ‘/mnt/tt/file.txt’: Input/output error
cp: failed to extend ‘/mnt/tt/file.txt’: Input/output error

Я хочу сохранить этот контент в файл.

2 ответа

Решение

В Linux (и других ОС) есть два основных потока вывода: стандартный вывод (stdout) и стандартная ошибка (stderr). Сообщения об ошибках, как те, которые вы показываете, печатаются со стандартной ошибкой. Классический оператор перенаправления (command > file) перенаправляет только стандартный вывод, поэтому стандартная ошибка по-прежнему отображается на терминале. Для перенаправления stderr у вас есть несколько вариантов:

  1. Перенаправить стандартный вывод в один файл и стандартный вывод в другой файл:

    command > out 2>error
    
  2. Перенаправить stderr на стандартный вывод (&1), а затем перенаправить стандартный вывод в файл:

    command >out 2>&1
    
  3. Перенаправить оба в файл:

    command &> out
    

Для получения дополнительной информации о различных операторах управления и перенаправления см. Здесь.

Первое, на что следует обратить внимание, это то, что есть несколько способов, в зависимости от вашей цели и оболочки, поэтому это требует небольшого понимания нескольких аспектов. Кроме того, некоторые команды, такие как time а также strace записывать вывод в stderr по умолчанию и может предоставлять или не предоставлять метод перенаправления, специфичный для этой команды

Основная теория, лежащая в основе перенаправления, заключается в том, что процесс, порожденный оболочкой (предполагается, что это внешняя команда, а не встроенная оболочка), создается с помощью fork() а также execve() системные вызовы, а до этого еще один системный вызов dup2() выполняет необходимые перенаправления перед execve() случается. В этом смысле перенаправления наследуются от родительской оболочки. m&>n а также m>n.txt сообщить оболочке о том, как выполнить open() а также dup2() системный вызов (см. также, как работает перенаправление ввода, в чем разница между перенаправлением и конвейером и что именно означает перенаправление вывода)

Перенаправления оболочки

Наиболее типичным является через 2> в Supratika Banerjee, таких как dash (который связан с /bin/sh) а также bash; первая - это оболочка по умолчанию и POSIX-совместимая, а вторая - то, что большинство пользователей используют для интерактивного сеанса. Они отличаются по синтаксису и возможностям, но, к счастью, для нас перенаправление потока ошибок работает одинаково (за исключением &> нестандартный). В случае csh и его производных, перенаправление stderr там не совсем работает.

Давайте вернемся к 2> часть. Обратите внимание на две ключевые вещи: > означает оператор перенаправления, где мы открываем файл и 2 целое число обозначает дескриптор файла stderr; на самом деле именно так стандарт POSIX для языка оболочки определяет перенаправление в разделе 2.7:

[n]redir-op word

Для простого > перенаправление, 1 целое число подразумевается для stdout т.е. echo Hello World > /dev/null это так же, как echo Hello World 1>/dev/null, Обратите внимание, что оператор целого числа или перенаправления не может быть заключен в кавычки, в противном случае оболочка не распознает их как таковые, а вместо этого обрабатывает как текстовую строку. Что касается пробелов, важно, чтобы целое число находилось рядом с оператором перенаправления, но файл может быть либо рядом с оператором перенаправления, либо нет, т.е. command 2>/dev/null а также command 2> /dev/null будет работать просто отлично.

Несколько упрощенный синтаксис для типичной команды в оболочке будет

 command [arg1] [arg2]  2> /dev/null

Хитрость в том, что перенаправление может появиться где угодно. Это оба 2> command [arg1] а также command 2> [arg1] действительны. Обратите внимание, что для bash оболочка, там существует &> способ перенаправить потоки stdout и stderr одновременно, но опять же - это зависит от bash, и если вы стремитесь к переносимости сценариев, он может не работать. Смотрите также Ubuntu Wiki и В чем разница между &> и 2> & 1.

Примечание: > оператор перенаправления усекает файл и перезаписывает его, если файл существует. 2>> может быть использован для добавления stderr в файл.

Если вы можете заметить, > предназначен для одной команды. Для сценариев мы можем перенаправить поток stderr всего сценария извне, как в myscript.sh 2> /dev/null или мы можем использовать встроенный exec. Встроенный exec обладает возможностью перезаписи потока для всего сеанса оболочки, так сказать, в интерактивном режиме или с помощью сценария. Что-то вроде

#!/bin/sh
exec 2> ./my_log_file.txt
stat /etc/non_existing_file

В этом примере файл журнала должен показывать stat: cannot stat '/etc/non_existing_file': No such file or directory,

Еще один способ - через функции. Как отметил Supratika Banerjee в своем ответе, мы можем написать объявление функции с уже прикрепленным перенаправлением, то есть

some_function(){
    command1
    command2
} 2> my_log_file.txt

Команды, пишущие исключительно в stderr

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

time echo foo 2>&1 > file.txt

альтернативно, синхронный список или подоболочка могут быть перенаправлены, если вы хотите разделить вывод (как показано в соответствующем посте):

{ time sleep 1 2> sleep.stderr ; } 2> time.txt

Другие команды, такие как strace или же dialog предоставить средства для перенаправления stderr. strace имеет -o <filename.txt> опция, которая позволяет указать имя файла, в который должен быть записан вывод. Существует также возможность записи текстового файла для каждого подпроцесса, который strace видит. dialog Команда записывает текстовый интерфейс пользователя в stdout, но выводит в stderr, поэтому для сохранения его вывода в переменную (потому что var=$(...) и конвейеры получают только stderr) нам нужно поменять местами дескрипторы файлов

result=$(dialog --inputbox test 0 0 2>&1 1>/dev/tty);

но кроме того, есть --output-fd флаг, который мы также можем использовать. Есть также метод именованных каналов. Я рекомендую прочитать связанный пост о dialog Команда для подробного описания того, что происходит.

Другие вопросы по тегам