Подтвердить что ты не робот

Труба только STDERR через фильтр

Есть ли способ в bash направить STDERR через фильтр, прежде чем объединять его с STDOUT? То есть я хочу

STDOUT ────────────────┐
                       ├─────> terminal/file/whatever
STDERR ── [ filter ] ──┘

скорее, чем

STDOUT ────┐
           ├────[ filter ]───> terminal/file/whatever
STDERR ────┘
4b9b3361

Ответ 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 этого ответа.