Як перенаправити stdout та stderr у файл та відобразити stderr на консоль?


18

Я знаю, як перенаправляти файл і використовувати tee; на базовому рівні. Так

$ alias outanderr='bash -c "echo stdout >&1; echo stderr >&2"'
# A fake "application" displaying both output and error messages.

$ outanderr 1>file      # redirect stdout to a file, display stderr
stderr

$ outanderr 2>file      # redirect stderr to a file, display stdout
stdout

$ outanderr 1>file 2>&1 # redirect both to a file, display nothing

$ outanderr | tee file; echo "-- file contents --" && cat file
# redirect stdout to a file, display both (note: order is messed up)
stderr
stdout
-- file contents --
stdout

$ outanderr 2>&1 | tee file; echo "-- file contents --" && cat file
# redirect both to a file, display both
stdout
stderr
-- file contents --
stdout
stderr

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

$ outanderr ???; echo "-- file contents --" && cat file
# redirect both to a file, display stderr
stderr
-- file contents --
stdout
stderr

Містить:

  • Припускаючи баш.
  • Порядок повинен зберігатися у файлі.
  • Зміст stderr відображається в режимі реального часу рядок, тобто відсутність буферизації.
  • Можна використовувати окремі файли сценаріїв.
  • Магія може знадобитися.

Скільки ви контролюєте outanderrпрограму?
Кевін

1
@Kevin Я думаю, що питання є більш загальним, ніж це. Ось outanderrлише псевдонім, який друкує рядок до stdout та інший до stderr. Ідея (якщо це можливо) полягає у створенні загального рішення, яке могло б працювати з будь-якою програмою, не змінюючи їх.
lgeorget

@lgeorget Я розумію це, але я не вірю, що в загальному рішенні можна суворо відповідати всім обмеженням, тому я бачив, чи зможемо ми отримати конкретне.
Кевін

@Igeorget має рацію.
TWiStErRob

Відповіді:


12
2>&1 >>outputfile | tee --append outputfile

Для легкого тестування:

echo -n >outputfile; bash -c "echo stdout >&1; echo stderr >&2" 2>&1 >>outputfile |
  tee --append outputfile; echo "outputfile:"; cat outputfile

Редагувати 1:

Це працює, записуючи stdout (тільки) у файл, роблячи sterr stdout таким чином, щоб він проходив через трубу, і маючи записати свій вихід у той самий файл.

Обидва записи повинні бути виконані в режимі додавання ( >>замість >), інакше обидва б перезаписали вихід один одного.

Оскільки труба є буфером, немає гарантії, що висновок відображається у файлі в потрібному порядку. Це навіть не змінилося, якби програма була підключена до обох дескрипторів файлів (дві труби). Для гарантованого замовлення обидва виходи повинні пройти по одному каналу та бути позначені відповідно. Або вам знадобляться якісь по-справжньому химерні речі:

  1. Якщо і stdout, і stderr були перенаправлені на файл (не один і той же файл!), І обидва файли були на томі FUSE, модуль FUSE міг позначити кожне записування часовою міткою, щоб друга програма могла правильно сортувати дані та комбінувати їх для реального вихідного файлу. Або ви не позначаєте дані, але змусили модуль створити комбінований вихідний файл. Швидше за все, ще немає модуля FUSE, який би це робив ...
  2. Як stdout, так і stderr можуть бути спрямовані на /dev/null. Виходи програми будуть відокремлені, запустивши його strace -f -s 32000 -e trace=write. У цьому випадку вам доведеться змінити втечу. Зайве говорити, що додаток не працює швидше шляхом їх відстеження.
  3. Можливо, те саме можна досягти, використовуючи існуючий, простий модуль FUSE і відстежуючи модуль замість програми. Це може бути швидше, ніж відстежувати додаток, оскільки (а точніше: якщо) модуль, ймовірно, має набагато менше системних викликів, ніж додаток.
  4. Якщо сама програма може бути змінена: Додаток можна зупинити після кожного виходу (але я думаю, що це можливо лише зсередини) і продовжувати лише після отримання сигналу s (SIGUSR1 або SIGCONT). Зчитування програми з труби повинно перевірити як трубу, так і файл на наявність нових даних та надсилати сигнал після кожного нового даних. Залежно від виду застосування це може бути швидшим або навіть повільніше, ніж метод страйсу. FUSE - це рішення з максимальною швидкістю.

1
Ба. Назвіть мене в середині написання точно тієї самої відповіді, чому цього не потрібно.
Кевін

2
Примітка: це умова перегонів, що вводить можливість заміни / помилки ліній, але я не думаю, що цього можна уникнути.
Кевін

1
@Kevin Це трапляється з найкращими з нас, я страждав від цього раніше і мало не попросив функцію "покажи мені, що хтось пише" (що було б складно). Мені здається, що умова перегонів виникає лише в тому випадку, якщо після запису в конвеєр відбувається запис у файл (stdout).
Hauke ​​Laging

Чи не посилав би це stdoutі stderrна tee, чи я щось пропускаю? Я думаю, що вимога ОП - tee stderrлише.
Джозеф Р.

@JosephR. Вам не трапилось спробувати?
Hauke ​​Laging
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.