Як перенаправити та додати як 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.