С bash, как я могу передать стандартную ошибку в другой процесс?

138

Хорошо известно, как передать стандартный вывод процесса в стандартный ввод другого процесса:

proc1 | proc2

Но что, если я хочу отправить стандартную ошибку proc1 в proc2 и оставить стандартный вывод в его текущем местоположении? Вы могли бы подумать, что bashбудет иметь команду в соответствии с:

proc1 2| proc2

Но, увы, нет. Есть какой-либо способ сделать это?

paxdiablo
источник
Вы можете сделать такое простое перенаправление в 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)), и это сломало мою оболочку, мне пришлось выйти и снова войти в систему.
Рольф
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(через -конец в конце).

По сути, это команда подкачки, которую вы видите в алгоритмах сортировки:

temp   = value1;
value1 = value2;
value2 = temp;
paxdiablo
источник
3
Какова ценность использования 1>&2-здесь, а не просто 1>&2? Я не понимаю, почему мы хотели бы закрыть fd 2, если мы просто собираемся открыть / переназначить его немедленно.
dubiousjim
1
@dubiousjim, никаких преимуществ в этом конкретном случае, я подозреваю, что сделал это просто для того, чтобы быть последовательным - закрытие дескриптора файла 3 - хорошая идея, чтобы освободить его.
paxdiablo
Хороший вопрос, @ovgolovin, я не могу поверить, что никто не поднял это за семь месяцев с тех пор, как я сделал это редактирование. Исправлено в соответствии с вашим предложением.
paxdiablo
пытаясь заставить make gcc (который в моей системе раскрашен) работать с этим "(make 3> & 1 1> & 2- 2> & 3-) | less -R" while "(ls -al 3> & 1 1> & 2- 2> & 3-) | less -R "работает как положено.
несинхронизировано
Похоже, ваши объяснения вернулись ко вторым двум перенаправлениям. 1> & 2 - устанавливает дескриптор файла 2 (оригинальный stderr) для обработки 1 (оригинальный stdout) 2> & 3 - устанавливает дескриптор файла 3 (исходный stderr) для обработки 2 (оригинальный stderr). Пожалуйста, поправьте меня, если я ошибаюсь. Кстати, я бы предположил, что черта на 2 состоит в том, чтобы предотвратить отправку новых данных stderr в этот буфер, пока он заполняется данными из stdout.
Агсмит
70

Bash 4 имеет эту особенность:

Если используется `| & ', стандартная ошибка command1 связана со стандартным вводом command2 через канал; это сокращение для 2> & 1 |. Это неявное перенаправление стандартной ошибки выполняется после любых перенаправлений, указанных в команде.

Zsh также имеет эту функцию.

-

С другими / более старыми оболочками, просто введите это явно как

FirstCommand 2> & 1 | OtherCommand

Приостановлено до дальнейшего уведомления.
источник
14
При чтении документов это делает как стандартную ошибку, так и вывод, а не просто stderr, но это приятно знать. Пора начать смотреть на bash 4, я думаю.
paxdiablo
Текущее руководство по bash гласит: «Если | & используется, стандартная ошибка команды, в дополнение к ее стандартному выводу, связана со стандартным входом command2». Это явно не то, что хочет ОП.
Питер - Восстановить Монику
@ PeterA.Schneider: ОП говорит, что «оставить стандартный вывод в его текущем местоположении», что может быть неоднозначным.
Приостановлено до дальнейшего уведомления.
Я не вижу никакой двусмысленности. Ваше предложение (1) объединяет два потока. (2) OtherCommandзаписывает объединенные данные где-то, возможно, где-то еще. Так что это не те же данные, и они потенциально собираются куда-то еще. Это примерно противоположно желанию ОП, не так ли?
Питер - Восстановить Монику
@ PeterA.Schneider: Где еще находится текущее местоположение стандартного выхода? Если proc1выводит в stdout и в stderr, и вы хотите, чтобы stderr proc2перешел к стандартному выводу (в котором находится стандартный вывод proc1), тогда мой ответ выполнит это. Я дал ОП, что он просил , возможно, не то, что он хотел попросить. В этом заключается потенциальная двусмысленность. ОП принял ответ, который меняет stdout и stderr, но это не то, что он просил.
Приостановлено до дальнейшего уведомления.
27

Обмен - это здорово, так как он решает проблему. На тот случай, если вам даже не нужен оригинальный стандартный вывод, вы можете сделать это следующим образом:

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

Порядок жизненно важен; вы бы не хотели

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

Как это перенаправит все на /dev/null!

kccqzy
источник
0

Ни один из них действительно не работал очень хорошо. Лучший способ сделать то, что вы хотели, это:

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

Это работает только в тех случаях, когда commandне требуется ввод с клавиатуры. например:

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

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

sbingner
источник