При использовании nohup для запуска команды в фоновом режиме в терминале появляется некоторое содержимое.
cp: error reading ‘/mnt/tt/file.txt’: Input/output error
cp: failed to extend ‘/mnt/tt/file.txt’: Input/output error
Я хочу сохранить это содержимое в файл.
В Linux (и других ОС) есть два основных потока вывода: стандартный вывод (stdout) и стандартная ошибка (stderr). Сообщения об ошибках, такие как те, что вы показываете, печатаются в стандартную ошибку. Классический оператор перенаправления (command > file
) перенаправляет только стандартный вывод, поэтому стандартная ошибка по-прежнему отображается на терминале. Чтобы перенаправить также и stderr, у вас есть несколько вариантов:
Перенаправить stdout в один файл, а stderr - в другой:
command >out 2>error
Перенаправьте stdout в файл (>out
), а затем перенаправьте stderr в stdout (2>&1
):
command >out 2>&1
Перенаправить обе команды в файл (это поддерживается не всеми оболочками, например, bash
и zsh
поддерживают это, а sh
и ksh
- нет):
command &> out
Более подробную информацию о различных операторах управления и перенаправления см. в здесь.
Прежде всего, следует отметить, что существует несколько способов, зависящих от вашей цели и оболочки, поэтому это требует небольшого понимания нескольких аспектов. Кроме того, некоторые команды, такие как time
и strace
, по умолчанию пишут вывод на stderr, и могут предоставлять или не предоставлять метод перенаправления, специфичный для этой команды.
Основная теория перенаправления заключается в том, что процесс, порожденный shell (предполагается, что это внешняя команда, а не встроенная в shell), создается с помощью системных вызовов fork()
и execve()
, а перед этим другой системный вызов dup2()
выполняет необходимые перенаправления, прежде чем произойдет execve()
. В этом смысле перенаправления наследуются от родительской оболочки. Команды m&>n
и m>n.txt
сообщают оболочке, как выполнять системные вызовы open()
и dup2()
(см. также Как работает перенаправление ввода, В чем разница между перенаправлением и трубой и Что означает & в перенаправлении вывода)
Наиболее типичным является использование 2>
в Bourne-подобных оболочках, таких как dash
(которая симлинкована с /bin/sh
) и bash
; первая является стандартной и POSIX-совместимой оболочкой, а вторая используется большинством пользователей для интерактивных сессий. Они отличаются синтаксисом и возможностями, но, к счастью для нас, перенаправление потока ошибок работает одинаково (за исключением &>
нестандартного). В случае csh и его производных перенаправление stderr не совсем работает.
Вернемся к 2>
части. Обратите внимание на два ключевых момента: >
означает оператор перенаправления, где мы открываем файл, а целое число 2
обозначает дескриптор файла stderr; на самом деле именно так определяет перенаправление стандарт POSIX для языка shell в разделе 2.7:
[n]redir-op word
Для простого >
перенаправления, целое число 1
подразумевается для stdout
, т.е. echo Hello World > /dev/null
- это то же самое, что echo Hello World 1>/dev/null
. Обратите внимание, что целое число или оператор перенаправления нельзя заключать в кавычки, иначе shell'не распознает их как таковые, а вместо этого будет воспринимать как литеральную строку текста. Что касается интервалов, то важно, чтобы целое число находилось рядом с оператором перенаправления, а файл может быть как рядом с оператором перенаправления, так и нет, т. е. command 2>/dev/null
и command 2> /dev/null
будут работать одинаково хорошо.
Несколько упрощенный синтаксис типичной команды в shell будет выглядеть так
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
.
Еще одним способом является использование функций. Как отметил в своем ответе kopciuszek, мы можем написать объявление функции с уже подключенным перенаправлением, то есть
some_function(){
command1
command2
} 2> my_log_file.txt
Такие команды, как time
и strace
, по умолчанию пишут свой вывод в stderr. В случае с командой time
единственной жизнеспособной альтернативой является перенаправление вывода всей команды, то есть
time echo foo 2>&1 > file.txt
В качестве альтернативы можно перенаправить синхронный список или подоболочку, если вы хотите разделить вывод (как показано в related post):
{ time sleep 1 2> sleep.stderr ; } 2> time.txt
Другие команды, такие как strace
или dialog
, предоставляют средства для перенаправления stderr. У strace
есть опция -o <filename.txt>
, которая позволяет указать имя файла, в который должен быть записан вывод. Также есть опция для записи текстового файла для каждого подпроцесса, который видит strace
. Команда dialog
записывает текстовый пользовательский интерфейс в stdout, но вывод в stderr, поэтому для того, чтобы сохранить вывод в переменную (поскольку var=$(...)
и pipelines принимает только stderr), нам нужно поменять местами дескрипторы файлов
result=$(dialog --inputbox test 0 0 2>&1 1>/dev/tty);
но кроме того, есть флаг --output-fd
, который мы также можем использовать. Существует также метод именованных труб. Я рекомендую прочитать связанный пост о команде dialog
для подробного описания происходящего.