Есть ли способ в bash пропустить STDERR через фильтр перед его объединением с STDOUT? То есть я хочу
STDOUT ────────────────┐
├─────> terminal/file/whatever
STDERR ── [ filter ] ──┘
скорее, чем
STDOUT ────┐
├────[ filter ]───> terminal/file/whatever
STDERR ────┘
Ответы:
Вот пример, смоделированный после того, как поменять местами дескрипторы файлов в bash . Вывод a.out следующий без префикса «STDXXX:».
STDERR: stderr output STDOUT: more regular ./a.out 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g' more regular stdErr output
Цитата из приведенной выше ссылки:
источник
3>&2 2>&1 1>&3-
.TL; DR:
Пример:
Это будет работать как в bash, так и в zsh. В наши дни Bash в значительной степени повсеместен, однако, если вам действительно нужно (действительно грубое) решение для POSIX
sh
, посмотрите здесь .Объяснение
Безусловно, самый простой способ сделать это - перенаправить STDERR с помощью замены процесса :
Таким образом, при подстановке процесса вы получаете имя файла.
Так же, как вы могли бы сделать:
ты можешь сделать
>&2
Редирект - хfilter
«s STDOUT обратно к первоначальному STDERR.источник
exec 2> >(while .. read .. echo)
сценария, работающего как служба systemd. journald захватывает fd2 службы и определяет уровень журнала по префиксу «<N>»: добавление<2>
к строкам вывода, и вы получаете уровень ОШИБКИ, назначенный записям журнала. Но иногда systemd был быстрее, чтобы убить всю группу процессов при выходе из основной, прежде чем она успела записать свое последнее, самое важное сообщение!Наивное использование подстановки процесса, кажется, позволяет фильтровать
stderr
отдельно отstdout
::; ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) out e:err
Обратите внимание , что
stderr
выходит наstderr
иstdout
наstdout
, которые мы можем видеть, завернув все это в другой субоболочке и перенаправление файлыo
иe
( ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) ) 1>o 2>e
источник
$
как командную строку. Тогда они часто пишут оболочки примеры , как:$ cat /var/log/syslog | fgrep ...
. Однако эту строку нельзя скопировать из-за расширения$
.:;
выглядит как приглашение, но, по сути, не работает с оболочкой; так что вы можете безопасно выбрать и вставить всю строку.TL; DR: (bash и zsh)
Пример:
Многие ответы в сети StackExchange имеют форму:
cat /non-existant 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g'
У этого есть встроенное предположение: этот файловый дескриптор 3 не используется для чего-то еще.
Вместо этого используйте именованный файловый дескриптор и
{ba,z}sh
выделите следующий доступный файловый дескриптор> = 10:cat /non-existant {tmp}>&1 1>&2 2>&$tmp {tmp}>&- | sed 's/e/E/g'
Обратите внимание, что именованные файловые дескрипторы не поддерживаются POSIX.
sh
.Другая проблема, связанная с вышеизложенным, заключается в том, что команду нельзя передать по конвейеру другим командам без повторной замены STDOUT и STDERR на их исходные значения.
Чтобы разрешить последующий конвейер в POSIX
sh
(и все еще предполагая, что FD 3 не используется), это усложняется :Итак, учитывая предположение и грубый синтаксис этого, вам, вероятно, будет лучше использовать более простой
bash
/zsh
синтаксис, показанный в TL; DR выше и объясненный здесь .источник
Я считаю, что использование замены процесса bash легче запомнить и использовать, поскольку оно почти дословно отражает исходное намерение. Например:
$ cat ./p echo stdout echo stderr >&2 $ ./p 2> >(sed -e 's/s/S/') | sed 's/t/T/' sTdout STderr
использует первую команду sed в качестве фильтра только для stderr, а вторую команду sed для изменения объединенного вывода.
Обратите внимание, что пробел после 2> является обязательным для правильного анализа команды.
источник
Последняя часть этой страницы Advanced Bash Scripting Guide - «перенаправление только stderr на канал».
Это может быть то, что вы хотите. Если нет, то какая-то другая часть ABSG сможет вам помочь, это отлично.
источник
Взгляните на именованные каналы:
источник
cat - err
нарушит чередование stdout и stderr?