Як перенаправити та додати як stdout, так і stderr до файлу з Bash?


1533

Щоб перенаправити stdout до усіченого файлу в Bash, я знаю, щоб використовувати:

cmd > file.txt

Щоб перенаправити stdout в Bash, додавши до файлу, я знаю, що використовувати:

cmd >> file.txt

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

cmd &> file.txt

Як перенаправити як stdout, так і stderr, що додаються до файлу? cmd &>> file.txtне працював для мене.


37
Я хотів би зазначити, що &> outfile - це специфічний код Bash (та інші), а не портативний. Шлях до переносу (схожий на додані відповіді) завжди був і залишається> outfile 2> & 1
TheBonsai

Відповіді:


1997
cmd >>file.txt 2>&1

Bash виконує переадресації зліва направо так:

  1. >>file.txt: Відкрийте file.txtв режимі додавання і переспрямуйте stdoutтуди.
  2. 2>&1: Перенаправлення stderrна "куди stdoutзараз йде" . У цьому випадку це файл, відкритий у режимі додавання. Іншими словами, &1повторне використання дескриптора файлів, який stdoutвикористовується зараз.

33
працює чудово! але чи є спосіб зрозуміти це чи слід ставитися до цього як до атомної конструкції?
flybywire

181
Це просте перенаправлення, заяви про переадресацію оцінюються, як завжди, зліва направо. >> файл: Червоний. ВИМКНЕННЯ до файлу (режим додавання) (скорочення файлу 1 >>) 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 до-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 демонструє рішення "баш-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


Ваш приклад зробить щось інше, ніж просив ОП: Він буде перенаправляти stderr You_commandна stdout та stdout You_commandв файл output.log. Крім того, він не додасть файл, але його перезапише.
пабук

Правильно: Дескриптором файлу можуть бути будь-які значення, що перевищують 3 для всіх інших файлів.
Ітачі

5
Ваша відповідь показує найпоширенішу помилку переадресації виводу: перенаправлення STDERR до місця, де STDOUT зараз вказує, і лише після цього перенаправлення STDOUT на файл. Це не призведе до переадресації STDERR до одного файлу. Порядок переадресації має значення.
Jan Wikholm

1
це означає, що я повинен спочатку переадресувати STDERROR на STDOUT, а потім перенаправити STDOUT у файл. 1 > output.log 2>&1
Квінт.чжоу

1
@ Quintus.Zhou Yup. Ваша версія переспрямовує помилку на зовнішній вигляд і одночасно виходить у файл.
Олексій Ярошевич

11

Я здивований, що майже десять років ніхто ще не публікував такого підходу:

Якщо ви використовуєте старіші версії bash там, де &>>їх немає, ви також можете зробити:

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

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

  1. Перенаправити stderr на stdout.
  2. Перенаправити нову stdout, додавши до файлу.

Також дужки усувають будь-яку неоднозначність порядку, особливо якщо ви хочете замість цього передати stdout та stderr до іншої команди.


Ця реалізація спричиняє один додатковий процес для запуску системи. Використання синтаксису cmd >> file 2>&1працює у всіх оболонках і не потребує додаткового процесу для запуску.
Мікко Ранталайнен

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