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

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

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

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

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

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

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

    command >out 2>&1
  3. Перенаправить оба в файл (это поддерживается не всеми оболочками, bash и zsh поддерживать его, например, но sh и ksh не делайте этого):

    command &> out

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

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

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

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

Наиболее типичным является то, что через 2> в Похожие на Борна раковины, такие как 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/shexec 2> ./my_log_file.txtstat /etc/non_existing_file

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

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

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 команда для подробного описания происходящего.

@terdon Это более конкретный вопрос, и он правильно отображается в поиске Google для более конкретного вопроса, что хорошо.

@nroose да, и он будет продолжать появляться, это не изменится. Но любые новые ответы должны касаться более общего вопроса.