З bash, як я можу передати стандартну помилку в інший процес?


138

Добре відомо, як передавати стандартний вихід процесу на інший стандартний вхід:

proc1 | proc2

Але що робити, якщо я хочу надіслати стандартну помилку proc1 до proc2 і залишити стандартний висновок, що йде в поточне місце? Ви можете подумати bash, що команда матиме рядки:

proc1 2| proc2

Але, на жаль, ні. Чи можна це зробити?


Ви можете зробити таке просте перенаправлення в rc, що є ще однією оболонкою. Наприклад: proc1 |[2] proc2. Хіба це не приємно? Не в bashтому.
Рольф

Відповіді:


169

Існує також процес заміщення . Що робить процес замінником файлу.
Ви можете надіслати stderrфайл у такий спосіб:

process1 2> file

Але ви можете замінити процес для файлу наступним чином:

process1 2> >(process2)

Ось конкретний приклад, який надсилається stderrяк на екран, так і додається до журналу

sh myscript 2> >(tee -a errlog)

23
Це правильно відповідає на поставлене запитання і має бути прийнятою відповіддю від @paxdiablo
mmlb

Я спробував це. Це не спрацювало ( weston --help 2> >(less)), і це зламало мою оболонку, я повинен був вийти та знову увійти.
Rolf

1
@Rolf якщо обидва weston --helpі lessочікуєте взаємодії з клавіатурою, але лише 1 з них отримує це, то ви можете опинитися в незручній ситуації. Спробуйте зробити тестування з чимось подібним grep. Крім того, ви можете виявити, що обидва входи миші / клавіатури в будь-якому випадку переходять до другої команди, а не до вестону.
BeowulfNode42

88

Ви можете використовувати наступний трюк для заміни stdout та stderr. Тоді ви просто використовуєте звичайну функціональність труби.

( proc1 3>&1 1>&2- 2>&3- ) | proc2

Якщо ви на початку stdoutі stderrобидва вказали на одне місце, це дасть вам те, що вам потрібно.

Те , що x>yтрохи робить , щоб змінити дескриптор файлу , xтак що тепер відправляє інформацію де дескриптор файлу в yданий час точок. Для нашого конкретного випадку:

  • 3>&1створює нову ручку, 3яка буде виводити на поточну ручку 1(оригінальний stdout), просто зберегти її десь для кінцевої точки кулі нижче.
  • 1>&2модифікує ручку 1(stdout) для виведення на поточну ручку 2(оригінал stderr).
  • 2>&3-модифікує ручку 2(stderr) для виведення на поточну ручку 3(оригінальний stdout), потім закриває ручку 3(через -кінець).

Це ефективно команда swap, яку ви бачите в алгоритмах сортування:

temp   = value1;
value1 = value2;
value2 = temp;

3
Яка цінність використання 1>&2-тут, а не просто 1>&2? Я не розумію, чому ми хотіли б закрити fd 2, якщо ми просто збираємося його знову відкрити / перепризначити.
сумнівним

1
@dubiousjim, немає жодної переваги в цьому конкретному випадку, я підозрюю, що я це зробив лише для того, щоб бути послідовним - закриття файлу 3 - це хороша ідея, щоб звільнити його.
paxdiablo

Хороший момент, @ovgolovin, я не можу повірити, що ніхто його не вибрав за сім місяців, відколи я змінив цю редакцію. Виправлено відповідно до вашої пропозиції.
paxdiablo

намагаючись змусити зробити gcc (який є кольоровим у моїй системі) для роботи з цим "(зробіть 3> & 1 1> & 2- 2> & 3-) | менше -R" тоді як "(ls -al 3> & 1 1> & 2- 2> & 3-) | менше -R "працює, як очікувалося.
несинхронізований

Схоже, ваші пояснення повертаються на передні для двох інших переадресацій. 1> & 2- встановлює ручку файлу 2 (оригінальний stderr) для обробки 1 (оригінальний stdout) 2> & 3- набір ручки файлу 3 (скопійований stdout) для обробки 2 (оригінальний stderr). Будь ласка, виправте мене, якщо я помиляюся. btw, я б здогадався, що тире на 2 - це запобігання надходженню нових даних stderr до цього буфера під час заповнення даних із stdout.
агсміт

70

Bash 4 має цю особливість:

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

zsh також має цю особливість.

-

З іншими / старішими оболонками просто введіть це явно як

FirstCommand 2> & 1 | Іншийкоманд


14
Якщо читати документи, це робить і стандартну помилку, і вихід, а не просто stderr, але це приємно знати. Час почати дивитися на удар 4, я думаю.
paxdiablo

Поточне керівництво bash говорить: "Якщо | & використовується, стандартна помилка команди, крім стандартного виводу, підключена до стандартного вводу command2". Це явно не те, чого хоче ОП.
Пітер - Відновіть Моніку

@ PeterA.Schneider: ОП каже: "залиште стандартний вихід у поточне місце", що може бути неоднозначним.
Призупинено до подальшого повідомлення.

Я не бачу жодної неоднозначності. Ваша пропозиція (1) поєднує два потоки. (2) OtherCommandзаписує об'єднані дані кудись, можливо, десь ще. Тож це не ті самі дані, і це потенційно перебуває десь в іншому місці. Це приблизно протилежне бажання ОП, чи не так?
Пітер - Відновіть Моніку

@ PeterA.Schneider: Де ще є поточне місцезнаходження стандартного виводу? Якщо proc1виходи в stdout і stderr, і ви хочете, щоб stderr перейшов до stdin of proc2(саме там йде stdout proc1), тоді моя відповідь цього досягає. Я дав ОП те, що він просив , можливо, не те, що він хотів просити. У цьому полягає потенційна неоднозначність. ОП прийняв відповідь на те, що замінює stdout і stderr, а це не те, що він просив.
Призупинено до подальшого повідомлення.

27

Обмін чудово, оскільки він вирішує проблему. На всякий випадок, якщо вам навіть не потрібен оригінальний stdout, ви можете це зробити так:

proc1 2>&1 1>/dev/null | proc2

Порядок життєво важливий; ви б не хотіли:

proc1 >/dev/null 2>&1 | proc1

Оскільки це перенаправить усе на /dev/null!


0

Жоден із них насправді не працював дуже добре. Найкращий спосіб, який я знайшов робити те, що ви хотіли, це:

(command < input > output) 2>&1 | less

Це працює лише у випадках, коли commandне потрібно вводити клавіатуру. наприклад:

(gzip -d < file.gz > file) 2>&1 | less

ставить менше помилок gzip

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