Как перенаправить stderr в файл [дубликат]

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

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

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

538
задан 18 May 2015 в 16:42

2 ответа

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

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

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

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

     команда &> наружу
    

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

805
ответ дан 18 May 2015 в 16:42

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

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

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

Наиболее типично, через 2> в Bourne-подобных оболочках , например 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 . Обратите внимание, что целочисленный оператор или оператор перенаправления не могут быть заключены в кавычки, иначе оболочка не распознает их как таковые и вместо этого рассматривает их как буквальную строку текста. Что касается интервала, важно, чтобы целое число было рядом с оператором перенаправления, но файл может быть либо рядом с оператором перенаправления, либо нет, то есть команда 2> / dev / null и команда 2> / dev / null будет работать нормально.

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

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

Уловка здесь в том, что перенаправление может появляться где угодно. То есть действительны как 2> команда [arg1] , так и команда 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': Нет такого файла или каталога .

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

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

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

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

26
ответ дан 22 November 2019 в 22:35

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

Похожие вопросы: