Как перенаправить и добавить как stdout, так и stderr в файл с помощью Bash?


1536

Чтобы перенаправить стандартный вывод в усеченный файл в Bash, я знаю использовать:

cmd > file.txt

Чтобы перенаправить стандартный вывод в Bash, добавив в файл, я знаю использовать:

cmd >> file.txt

Чтобы перенаправить как stdout, так и stderr в усеченный файл, я знаю использовать:

cmd &> file.txt

Как перенаправить как stdout, так и stderr при добавлении в файл? cmd &>> file.txtне работал для меня.


37
Я хотел бы отметить, что &> outfile - это специфичный для Bash (и других) код, а не переносимый. Путь к переносимости (аналогично добавлению ответов) всегда был и остается> outfile 2> & 1
TheBonsai

Ответы:


1999
cmd >>file.txt 2>&1

Bash выполняет перенаправления слева направо следующим образом:

  1. >>file.txt: Открыть file.txtв режиме добавления и перенаправить stdoutтуда.
  2. 2>&1: Перенаправить stderrна «куда stdoutидет» . В данном случае это файл, открытый в режиме добавления. Другими словами, &1повторно использует дескриптор файла, который stdoutиспользуется в настоящее время.

33
работает отлично! но есть ли способ понять это или я должен относиться к этому как к атомарной конструкции bash?
flybywire

181
Это простое перенаправление, операторы перенаправления оцениваются, как всегда, слева направо. >> файл: красный. STDOUT to file (режим добавления) (сокращение от 1 >> file) 2> & 1: Красный. STDERR в «куда идет stdout» Обратите внимание, что интерпретация «перенаправить STDERR в STDOUT» неверна.
TheBonsai

31
Он говорит «добавить вывод (stdout, дескриптор файла 1) в file.txt и отправить stderr (дескриптор файла 2) в то же место, что и fd1».
Приостановлено до дальнейшего уведомления.

2
@TheBonsai, однако, что если мне нужно перенаправить STDERR в другой файл, но добавить? Это возможно?
возник

41
если вы делаете cmd >>file1 2>>file2это должно достичь того, что вы хотите.
Вудроу Дуглас

367

Есть два способа сделать это, в зависимости от вашей версии Bash.

Классический и портативный ( Bash pre-4 ) способ это:

cmd >> outfile 2>&1

Непортативный способ, начиная с Bash 4 :

cmd &>> outfile

(аналог &> outfile)

Для хорошего стиля кодирования, вы должны

  • решить, является ли переносимость проблемой (тогда используйте классический способ)
  • решить, является ли переносимость даже для Bash pre-4 проблемой (тогда используйте классический способ)
  • независимо от того, какой синтаксис вы используете, не меняйте его в одном и том же сценарии (путаница!)

Если ваш сценарий уже начинается с #!/bin/sh(независимо от того, предназначен он или нет), то решение Bash 4 и вообще любой специфичный для Bash код не годятся.

Также помните, что Bash 4 &>>- просто более короткий синтаксис - он не вводит никакой новой функциональности или чего-то подобного.

Синтаксис (помимо другого синтаксиса перенаправления) описан здесь: http://bash-hackers.org/wiki/doku.php/syntax/redirection#appending_redirected_output_and_error_output


8
Я предпочитаю & >>, так как это соответствует &> и >>. Также проще прочитать «добавить вывод и ошибки в этот файл», чем «отправить ошибки на вывод, добавить вывод в этот файл». Обратите внимание, что хотя Linux обычно имеет текущую версию bash, OS X, на момент написания, по-прежнему требует, чтобы bash 4 устанавливался вручную через homebrew и т. Д.
mikemaccana

Мне это нравится больше, потому что оно короче и только в двух местах на строку, так что, например, zsh сделает из "& >>"?
Филип

Также важно отметить, что в задании cron вы должны использовать синтаксис pre-4, даже если в вашей системе установлен Bash 4.
hyperknot

5
@zsero cron вообще не использует bash ... он использует sh. Вы можете изменить оболочку по умолчанию, предваряя SHELL=/bin/bashк crontab -eфайлу.
Рэй Фосс

89

В Bash вы также можете явно указать ваши перенаправления в разные файлы:

cmd >log.out 2>log_error.out

Добавление будет:

cmd >>log.out 2>>log_error.out

6
Перенаправление двух потоков в один и тот же файл с использованием вашей первой опции приведет к тому, что первый будет писать «поверх» второго, перезаписывая часть или все содержимое. Вместо этого используйте cmd >> log.out 2> log.out .
Орестис П.

3
Спасибо, что поймали это; вы правы, один будет бить другого. Однако ваша команда тоже не работает. Я думаю, что единственный способ записать в тот же файл, как это было сделано ранее cmd >log.out 2>&1. Я редактирую свой ответ, чтобы удалить первый пример.
Аарон Р.

65

В Bash 4 (а также в ZSH 4.3.11):

cmd &>>outfile

просто из коробки


2
@all: это хороший ответ, так как он работает с bash и является кратким, поэтому я отредактировал, чтобы он явно упоминал bash.
mikemaccana

10
@mikemaccana: ответ TheBonsai показывает решение bash 4 с 2009 года
JFS

52

Это должно работать нормально:

your_command 2>&1 | tee -a file.txt

Он будет хранить все журналы в файле file.txt, а также выводить их на терминал.


Это правильный ответ, если вы хотите видеть вывод в терминале тоже. Однако это был не тот вопрос, который изначально задавался.
Микко Ранталайнен

25

Попробуй это

You_command 1>output.log  2>&1

Ваше использование &> x.file работает в bash4. простите за это : (

Вот несколько дополнительных советов.

0, 1, 2 ... 9 - файловые дескрипторы в bash.

0 обозначает stdin, 1 обозначает stdout, 2 обозначает stderror. 3 ~ 9 является запасным для любого другого временного использования.

Любой файловый дескриптор может быть перенаправлен на другой файловый дескриптор или файл с помощью оператора >или >>(добавления).

Использование: < file_descriptor > > < имя_файла | & file_descriptor >

Пожалуйста, обратитесь к http://www.tldp.org/LDP/abs/html/io-redirection.html


Ваш пример будет делать что-то отличное от запрошенного OP: он перенаправит stderr of You_commandв stdout, а stdout You_command- в файл output.log. Кроме того, он не будет добавлен в файл, но перезапишет его.
Пабук

Правильно: дескриптор файла может иметь любые значения, которые больше 3 для всех остальных файлов.
Итачи

5
Ваш ответ показывает наиболее распространенную ошибку перенаправления вывода: перенаправление STDERR туда, куда в данный момент указывает STDOUT, и только после этого перенаправление STDOUT в файл. Это не приведет к перенаправлению STDERR в тот же файл. Порядок перенаправлений имеет значение.
Ян Викхольм

1
Означает ли это, я должен сначала перенаправить STDERROR в STDOUT, а затем перенаправить STDOUT в файл. 1 > output.log 2>&1
Quintus.Zhou

1
@ Quintus.Zhou Да. Ваша версия перенаправляет ошибку на выход и одновременно на файл.
Алексей Ярошевич

11

Я удивлен, что за почти десять лет никто еще не опубликовал этот подход:

Если вы используете более старые версии bash там, где их &>>нет, вы также можете сделать:

(cmd 2>&1) >> file.txt

Это порождает подоболочку, поэтому она менее эффективна, чем традиционный подход cmd >> file.txt 2>&1, и, следовательно, не будет работать для команд, которым необходимо изменить текущую оболочку (например cd, pushd), но этот подход кажется мне более естественным и понятным:

  1. Перенаправить stderr на стандартный вывод.
  2. Перенаправить новый стандартный вывод, добавив в файл.

Кроме того, круглые скобки устраняют любую двусмысленность порядка, особенно если вы хотите вместо этого направить stdout и stderr в другую команду.


Эта реализация вызывает один дополнительный процесс для запуска системы. Использование синтаксиса cmd >> file 2>&1работает во всех оболочках и не требует дополнительного процесса для запуска.
Микко Ранталайнен

@MikkoRantalainen Я уже объяснил, что он порождает подоболочку и менее эффективен. Смысл этого подхода заключается в том, что если эффективность не имеет большого значения (а это редко бывает), этот способ легче запомнить и труднее ошибиться.
Джеймсдлин
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.