Як перенаправити вихід у файл та stdout


988

У bash, виклик fooбуде відображати будь-який вихід з цієї команди на stdout.

Виклик foo > outputбуде перенаправляти будь-який вихід з цієї команди на вказаний файл (у цьому випадку 'вихід').

Чи є спосіб перенаправити вихід у файл і відобразити його у stdout?


3
Якщо хтось щойно опинився тут, шукаючи виведення помилок у файл, подивіться на - unix.stackexchange.com/questions/132511/…
Мерфі

2
Зауваження по термінології: при виконанні foo > outputданих буде виводиться на стандартний висновок і стандартний висновок є файл з ім'ям output. Тобто запис у файл - це запис у stdout. Ви запитуєте, чи можна записати і в stdout, і в термінал.
Вільям Перселл

2
@WilliamPursell Я не впевнений, що ваше пояснення покращує речі :-) Як щодо цього: ОП запитує, чи можна направити виклик програми, що викликається, як на файл, так і на виклик виклику програми (останній є тим, що виклик програми буде успадковуйте, якщо нічого особливого не було зроблено; тобто термінал, якщо програма виклику - це інтерактивна сесія bash). І, можливо, вони також хочуть керувати stderr викликаної програми аналогічно ("будь-який вихід з цієї команди" може бути розумно інтерпретований і означає, включаючи stderr).
Дон Хетч

Відповіді:


1379

Команда, яку ви бажаєте, називається tee:

foo | tee output.file

Наприклад, якщо ви дбаєте лише про stdout:

ls -a | tee output.file

Якщо ви хочете включити stderr, зробіть:

program [arguments...] 2>&1 | tee outfile

2>&1перенаправляє канал 2 (stderr / стандартна помилка) в канал 1 (stdout / стандартний вихід), таким чином, що обидва записуються як stdout. Він також спрямований на даний вихідний файл, як і з teeкоманди.

Крім того, якщо ви хочете додати файл журналу, використовуйте tee -aяк:

program [arguments...] 2>&1 | tee -a outfile

173
Якщо ОП хоче, щоб "весь вихід" був перенаправлений, вам також потрібно буде схопити stderr: "ls -lR / 2> & 1 | tee output.file"
Джеймс Брейді

45
@evanmcdonnal Відповідь не є помилковою, вона може бути недостатньо конкретною або повною, залежно від ваших вимог. Звичайно, існують умови, коли ви, можливо, не хочете stderr, оскільки частина виводу зберігається у файлі. Коли я відповів на це 5 років тому, я припустив, що ОП бажає лише стидуду, оскільки він згадував stdout у темі поста.
Зоредаче

3
Ах вибачте, я, можливо, трохи розгубився. Коли я спробував це, у мене просто не було результатів, можливо, все було складніше.
evanmcdonnal

38
Використовуйте -aаргумент на teeдодавання вмісту до нього output.file, а не перезаписуйте його:ls -lR / | tee -a output.file
kazy

16
Якщо ви користуєтесь $?згодом, він поверне код статусу tee, який, мабуть, не є тим, що ви хочете. Натомість можна використовувати ${PIPESTATUS[0]}.
LaGoutte

501
$ program [arguments...] 2>&1 | tee outfile

2>&1скидає потоки stderr та stdout. tee outfileбере потік, який він отримує, і записує його на екран і у файл "outfile".

Це, мабуть, те, що шукає більшість людей. Ймовірна ситуація, коли якась програма чи сценарій довго працюють і дають багато результатів. Користувач хоче періодично перевіряти його на наявність прогресу, але також хоче, щоб результат був записаний у файл.

Проблема (особливо при змішуванні потоків stdout та stderr) полягає в тому, що існує залежність від потоків, які промиваються програмою. Якщо, наприклад, всі записи на стандартний висновок будуть НЕ почервонів, але все записи в STDERR є почервонів, то вони будуть в кінцевому підсумку з хронологічної послідовності в вихідному файлі та на екрані.

Також погано, якщо програма повідомляє про хід лише 1 або 2 рядки кожні кілька хвилин. У такому випадку, якби результат не був пропущений програмою, користувач навіть години не бачив би жодного виводу на екрані, тому що жоден з них не проштовхувався б через трубу годинами.

Оновлення: Програма unbuffer, яка є частиною expectпакету, вирішить проблему буферизації. Це призведе до негайного запису stdout та stderr на екран та файл та збереження синхронізації при їх поєднанні та переадресації tee. Наприклад:

$ unbuffer program [arguments...] 2>&1 | tee outfile

7
Хтось знає про "unbuffer" для OSX?
Джон Мі

7
Якщо ви не можете використовувати unbuffer, GNU coreutils включає в себе інструмент під назвою stdbuff, який може бути використаний для запобігання буферизації виводу, як так$ stdbuf -o 0 program [arguments...] 2>&1 | tee outfile
Петро

1
Якщо ви використовуєте OS X, в більшості випадків використовувати розблокувальник незначно простіше, хоча ні, якщо ви хочете передавати сигнали команді, яку виконуєте. Мій коментар був більше спрямований на користувачів, які перебувають у Linux, де coreutils, швидше за все, встановлений за замовчуванням. @Ethan см ця відповідь , якщо ви плутати про stdbuf синтаксисом: stackoverflow.com/a/25548995/942781
Пітер

3
Зверніть увагу, що pythonвбудована опція, -uяка розблоковує вихід.
fabian789

1
Абсолютний рятувальник для навчання моделей ML, де я хочу ввійти без додаткового коду, але також побачити результат протягом годин / днів, необхідних для запуску, дякую!
рококо

126

Ще один спосіб, який працює для мене, це:

<command> |& tee  <outputFile>

як показано в посібнику з gnu bash

Приклад:

ls |& tee files.txt

Якщо використовується "| &", стандартна помилка command1 , крім стандартного виводу , підключається до стандартного вводу command2 через трубу; це скорочення для 2> & 1 |. Це неявне перенаправлення стандартної помилки на стандартний висновок виконується після будь-яких перенаправлень, визначених командою.

Для отримання додаткової інформації дивіться переадресацію


10
Якщо ви користуєтесь $?згодом, він поверне код статусу tee, який, мабуть, не є тим, що ви хочете. Натомість можна використовувати ${PIPESTATUS[0]}.
LaGoutte

1
Цей метод відкидає кольоровий вихід консолі, будь-які ідеї?
shakram02

Спробуйте: unbuffer ls -l --color = auto | tee files.txt
Лучано Андресс Мартіні

17

Ви можете в першу чергу використовувати рішення Zoredache , але якщо ви не хочете перезаписувати вихідний файл, слід написати tee з опцією -a таким чином:

ls -lR / | tee -a output.file

11

Що додати ...

У розпакувальника пакунків є проблеми з підтримкою деяких пакетів під Fedora та Redhat Unix.

Не допускаючи неприємностей

Слідом працював для мене

bash myscript.sh 2>&1 | tee output.log

Дякую, ScDF & matthew ваші вклади заощадили мені багато часу.



3

Бонусна відповідь, оскільки цей випадок використання привів мене сюди:

У тому випадку, коли вам потрібно зробити це як інший користувач

echo "some output" | sudo -u some_user tee /some/path/some_file

Зауважте, що відлуння відбуватиметься так, як ви, і запис файлу відбудеться як "some_user", що НЕ буде працювати, якщо ви запустили ехо як "some_user" і перенаправляєте вихід з >> "some_file", тому що перенаправлення файлу відбудеться як ти.

Підказка: tee також підтримує додавання зі знаком -a, якщо вам потрібно замінити рядок у файлі як інший користувач, ви можете виконати sed як потрібний користувач.


2

< command > |& tee filename # це створить файл "ім'я файлу" зі статусом команди як вміст. Якщо файл вже існує, він видалить існуючий вміст і запише статус команди.

< command > | tee >> filename # це додасть статус до файлу, але він не надрукує стан команди на standard_output (екран).

Я хочу надрукувати щось за допомогою "ехо" на екрані та додати дані, що лунають у файлі

echo "hi there, Have to print this on screen and append to a file" 

1

Ви можете зробити це для всього свого сценарію, використовуючи щось подібне на початку сценарію:

#!/usr/bin/env bash

test x$1 = x$'\x00' && shift || { set -o pipefail ; ( exec 2>&1 ; $0 $'\x00' "$@" ) | tee mylogfile ; exit $? ; }

# do whaetever you want

Це перенаправлення і виводить stderr і stdout у файл, який називається, mylogfile і нехай все одночасно йде до stdout .

Використовуються кілька дурних хитрощів:

  • використовувати execбез команди для встановлення переадресацій,
  • використовувати teeдля дублювання виходів,
  • перезавантажте скрипт із потрібними переспрямуваннями,
  • використовувати спеціальний перший параметр (простий NULсимвол, визначений $'string'спеціальним позначенням bash), щоб вказати, що сценарій перезапускається (жоден еквівалентний параметр не може використовуватися вашою оригінальною роботою),
  • спробуйте зберегти початковий статус виходу при перезапуску сценарію за допомогою pipefailпараметра.

Некрасивий, але корисний для мене в певних ситуаціях.


-13

Трійник ідеально підходить для цього, але це також зробить роботу

ls -lr / > output | cat output

10
Це помилка, якщо виводу вже не існує, і він не робить те, що ви хочете, якщо він робить, загалом це безглуздо. Можливо, ви мали на увазі ";" замість "|" ?
Роберт Гембл

6
Навіть якщо ви використовували a ;, вихід буде сильно затримуватися під час повільної команди.
Бред Кох
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.