Труба только STDERR через фильтр
Есть ли способ в bash направить STDERR через фильтр, прежде чем объединять его с STDOUT? То есть я хочу
STDOUT ────────────────┐
├─────> terminal/file/whatever
STDERR ── [ filter ] ──┘
скорее, чем
STDOUT ────┐
├────[ filter ]───> terminal/file/whatever
STDERR ────┘
Ответы
Ответ 1
Вот пример, смоделированный после как заменить файловые дескрипторы в 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
Цитата из приведенной выше ссылки:
- Сначала сохраните stdout как & 3 (& 1 обмануто в 3)
- Затем отправьте stdout на stderr (& 2 обмануто на 1)
- Отправить stderr в & 3 (stdout) (& 3 дублируется на 2)
- close & 3 (& - дублируется в 3)
Ответ 2
Наивное использование замещения процесса, по-видимому, позволяет фильтровать 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
Ответ 3
Я считаю, что замену процесса 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 > является обязательным для правильной обработки команды.
Ответ 4
Последняя часть this page в Расширенном Bash Scripting Guide - это перенаправление только stderr на труба".
# Перенаправление только stderr в канал.
exec 3>&1 # Save current "value" of stdout.
ls -l 2>&1 >&3 3>&- | grep bad 3>&- # Close fd 3 for 'grep' (but not 'ls').
# ^^^^ ^^^^
exec 3>&- # Now close it for the remainder of the script.
# Спасибо, S.C.
Это может быть то, что вы хотите. Если нет, какая-то другая часть ABSG должна помочь вам, это отлично.
Ответ 5
Взгляните на именованные каналы:
$ mkfifo err
$ cmd1 2>err |cat - err |cmd2
Ответ 6
TL; DR:
$ cmd 2> >(stderr-filter >&2)
Пример:
% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%
Это будет работать как в bash, так и в zsh. В наше время Bash довольно распространен, однако, если вам действительно нужно (действительно грубое) решение для POSIX sh
, тогда смотрите здесь.
объяснение
Безусловно, самый простой способ сделать это - перенаправить STDERR через подстановку процесса:
Замена процесса позволяет ссылаться на вход или выход процесса, используя имя файла. Это принимает форму
>(list)
Список процессов запускается асинхронно, а его ввод или вывод отображается в виде имени файла.
Итак, что вы получите с заменой процесса - это имя файла.
Так же, как вы могли бы сделать:
$ cmd 2> filename
ты можешь сделать
$ cmd 2> >(filter >&2)
filter
перенаправления >&2
STDOUT возвращается к исходному стандарту STDERR.
Ответ 7
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 не используется), это усложняется:
(cmd 2>&1 >&3 3>&- | stderr-filter >&2 3>&-) 3>&1
Итак, учитывая предположения и грубый синтаксис этого, вам, вероятно, будет лучше использовать более простой синтаксис bash
/zsh
этого ответа.