Трубить как stdout, так и stderr в bash?

156

Кажется, что в более новых версиях bash есть &>оператор, который (если я правильно понимаю) перенаправляет как stdout, так и stderr в файл ( &>>вместо этого добавляет файл, как пояснил Адриан).

Какой самый простой способ добиться того же, но вместо того, чтобы передать другую команду?

Например, в этой строке:

cmd-doesnt-respect-difference-between-stdout-and-stderr | grep -i SomeError

Я бы хотел, чтобы grep совпадал с контентом как в stdout, так и в stderr (по сути, объединить их в один поток).

Примечание : этот вопрос касается вопросов о трубопроводах, а не о перенаправлении, поэтому он не является дубликатом вопроса, который в настоящее время помечен как дубликат.

Эндрю Ферье
источник
См. Второй ответ ( stackoverflow.com/a/637834/1129642 ) на связанный вопрос для правильного способа передачи как stdout, так и stderr. Нет необходимости в другом вопросе.
Marki555
4
@triplee Не точный дубликат, не так ли? Труба против перенаправления в файл?
Бенджамин В.
@ BenjaminW Там есть по крайней мере один ответ, который решает оба сценария, хотя это не принятый ответ. Это довольно распространенный вопрос, поэтому мы могли бы найти лучший дубликат или попросить модератора объединить их - или даже, в худшем случае, создать совершенно новую каноническую тему для этой темы. Если вы найдете лучший обман, непременно предложите его. Заранее спасибо.
tripleee
12
@tripleee Решает, да, но ни один из ответов не использует |&ярлык, который, на мой взгляд, является наиболее удобным решением для «перенаправления как stdout, так и stderr в канал».
Бенджамин В.
3
Это не дубликат связанного вопроса, и не было ясно, что ответ Марко сделал то, что я хотел. Также не упоминается | &. Голосование возобновить.
Мартин Боннер поддерживает Монику

Ответы:

163

(Обратите внимание, что &>>file добавление в файл while &>приведет к перенаправлению и перезаписи ранее существующего файла.)

Чтобы объединить, stdoutи stderrвы перенаправили бы последнее на первое использование 2>&1. Это перенаправляет stderr (дескриптор файла 2) в stdout (дескриптор файла 1), например:

$ { echo "stdout"; echo "stderr" 1>&2; } | grep -v std
stderr
$

stdoutидет в стандартный вывод, stderrидет в стандартный вывод. grepтолько видит stdout, значит stderrраспечатывает на терминал.

С другой стороны:

$ { echo "stdout"; echo "stderr" 1>&2; } 2>&1 | grep -v std
$

После записи в stdout и stderr 2>&1перенаправляет stderr обратно в stdout и grepвидит обе строки в stdin, таким образом отфильтровывая обе.

Вы можете прочитать больше о перенаправлении здесь .

Что касается вашего примера (POSIX):

cmd-doesnt-respect-difference-between-stdout-and-stderr 2>&1 | grep -i SomeError

или, используя >=bash-4:

cmd-doesnt-respect-difference-between-stdout-and-stderr |& grep -i SomeError
Адриан Фрювирт
источник
Спасибо за разъяснения по &>>. Я исправил свой вопрос.
Эндрю Ферье
18
Я добавил ваш пример к своему ответу, на случай, если он не был очевиден на основании моих приведенных примеров. Как примечание, вы также можете использовать специфичные для bash |&вместо 2>&1 |.
Адриан Фрювирт
13
Дополнительное замечание о |&ярлыке, предложенном @ AdrianFrühwirth для будущих читателей: эта функция поддерживается только в bashверсии 4+. Если вы используете 3 или ниже, вы должны придерживаться 2>&1 |.
Tomocafe
3
Перенаправление Bash очень хорошо объяснено здесь . @ AdrianFrühwirth проделала хорошую работу, вставленная ссылка идет еще дальше. Иногда мне бы хотелось, чтобы официальная документация Bash была такой хорошей.
Дэвид Андреолетти
112

У Bash есть сокращение 2>&1 |, а именно |&, какие каналы и stdout, и stderr (см. Руководство ):

cmd-doesnt-respect-difference-between-stdout-and-stderr |& grep -i SomeError

Это было введено в Bash 4.0, см. Примечания к выпуску .

Бенджамин В.
источник
Спасибо за добавление этого для полноты. Я собираюсь оставить другой ответ правильным, так как многие до сих пор используют bash pre-4.0. Но это полезно.
Эндрю Ферье
9
Наиболее вероятно, что Bash, который поставляется на macOS, слишком стар, чтобы поддерживать это.
Flimm
@Flimm, но зш нет
Трентон
1
Поскольку ksh использует | & для coproc, это кажется плохим выбором для ненужных сокращений. Я ненавижу видеть строки со стеком дупсов и перенаправлений столько же, сколько у следующего парня, но есть кое-что, что нужно сказать за откровенность ... и я прошу прощения, что этот комментарий не добавляет много. Я просто хотел выразить отвращение к стенографии, не отрицая фактически полезный ответ, потому что это хорошо, что люди видят это. Я этого не знал, так что спасибо, что предупредил меня.
Пол Ходжес
@PaulHodges Я согласен, что он не переносимый - мне в основном нравится использовать его для интерактивных сессий Bash, чтобы не набирать слишком много текста.
Бенджамин В.