bash 仅通过过滤器输送 STDERR

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3618078/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 19:38:13  来源:igfitidea点击:

Pipe only STDERR through a filter

linuxbashredirect

提问by Martin DeMello

Is there any way, in bash, to pipe STDERR through a filter before unifying it with STDOUT? That is, I want

在 bash 中,有没有办法在将 STDERR 与 STDOUT 统一之前通过过滤器将其通过管道传输?也就是说,我想要

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

rather than

而不是

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

采纳答案by Paul Rubel

Here's an example, modeled after how to swap file descriptors in bash. The output of a.out is the following, without the 'STDXXX: ' prefix.

这是一个示例,模仿如何在 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

Quoting from the above link:

引用上面的链接:

  1. First save stdout as &3 (&1 is duped into 3)
  2. Next send stdout to stderr (&2 is duped into 1)
  3. Send stderr to &3 (stdout) (&3 is duped into 2)
  4. close &3 (&- is duped into 3)
  1. 首先将标准输出保存为 &3(&1 被复制为 3)
  2. 接下来将标准输出发送到标准错误(&2 被欺骗为 1)
  3. 将 stderr 发送到 &3 (stdout)(&3 被欺骗成 2)
  4. 关闭 &3 (&- 被欺骗成 3)

回答by solidsnack

A naive use of process substitution seems to allow filtering of stderrseparately from stdout:

进程替换的幼稚使用似乎允许stderrstdout以下各项中单独过滤:

:; ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 )
out
e:err

Note that stderrcomes out on stderrand stdouton stdout, which we can see by wrapping the whole thing in another subshell and redirecting to files oand e

需要注意的是stderr出来上stderrstdoutstdout,我们可以在另一个子shell包裹了整个事情,并重定向到文件看到oe

( ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) ) 1>o 2>e

回答by Tom Hale

TL;DR:

特尔;博士:

$ cmd 2> >(stderr-filter >&2)

Example:

例子:

% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%

This will work in both bash and zsh. Bash is pretty much ubiquitous these days, however, if you really do need a (really gnarly) solution for POSIX sh, then see here.

这将适用于 bash 和 zsh。如今,Bash 几乎无处不在,但是,如果您确实需要一个(非常粗糙的)POSIX 解决方案sh请参阅此处



Explanation

解释

By far, the easiest way to do this is to redirect STDERR via process substitution:

到目前为止,最简单的方法是通过进程替换重定向 STDERR :

Process substitution allows a process's input or output to be referred to using a filename. It takes the form of

>(list)

The process list is run asynchronously, and its input or output appears as a filename.

进程替换允许使用文件名引用进程的输入或输出。它采用以下形式

>(list)

进程列表异步运行,其输入或输出显示为文件名。

So what you get with process substituion is a filename.

所以你用进程替换得到的是一个文件名。

Just like you could do:

就像你可以这样做:

$ cmd 2> filename

you can do

你可以做

$ cmd 2> >(filter >&2)

The >&2redirect's filter's STDOUT back to the original STDERR.

>&2重定向的filter的STDOUT回到原来的STDERR。

回答by Tom Hale

TL;DR: (bash and zsh)

TL;DR:(bash 和 zsh)

$ cmd 2> >(stderr-filter >&2)

Example:

例子:

% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%


Many answers on the StackExchange network have the form:

StackExchange 网络上的许多答案都具有以下形式:

cat /non-existant 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g'

This has a built-in assumption: that file descriptor 3 isn't being used for something else.

这有一个内置假设:文件描述符 3 没有用于其他用途。

Instead, use a named file descriptor, and {ba,z}shwill allocate the next available file descriptor >= 10:

相反,使用命名的文件描述符,{ba,z}sh并将分配下一个可用的文件描述符 >= 10:

cat /non-existant {tmp}>&1 1>&2 2>&$tmp {tmp}>&- | sed 's/e/E/g'

Note that named file descriptors aren't supported by POSIX sh.

请注意, POSIX 不支持命名文件描述符sh

The other issue with the above is that the command cannot be piped to further commands without again swapping STDOUT and STDERR back to their original values.

上面的另一个问题是,如果不再次将 STDOUT 和 STDERR 交换回其原始值,则无法将命令通过管道传输到其他命令。

To allow onward piping in POSIX sh, (and still assuming FD 3 is not it use) it gets complicated:

为了允许在 POSIX 中继续管道sh,(并且仍然假设不使用 FD 3)它变得复杂

(cmd 2>&1 >&3 3>&- | stderr-filter >&2 3>&-) 3>&1

So, Given the assumption and gnarly syntax of this, you're likely to be better off using the simpler bash/zshsyntax shown in the TL;DR above, and explained here.

因此,鉴于此假设和粗糙的语法,您可能最好使用上面 TL;DR 中显示的更简单的bash/zsh语法,并在此处解释。

回答by Pecunifex

I find the use of bash process substitution easier to remember and use as it reflects the original intention almost verbatim. For example:

我发现使用 bash 进程替换更容易记住和使用,因为它几乎逐字反映了初衷。例如:

$ cat ./p
echo stdout
echo stderr >&2
$ ./p 2> >(sed -e 's/s/S/') | sed 's/t/T/'
sTdout
STderr

uses the first sed command as a filter on stderr only and the second sed command to modify the joined output.

使用第一个 sed 命令作为仅对 stderr 的过滤器,使用第二个 sed 命令来修改连接的输出。

Note that the white space after 2> is mandatory for the command to be parsed correctly.

请注意,2> 之后的空格是正确解析命令所必需的。

回答by signine

The last part of this pageof the Advanced Bash Scripting Guide is "redirecting only stderr to a pipe".

Advanced Bash Scripting Guide本页的最后一部分是“仅将 stderr 重定向到管道”。

# Redirecting only stderr to a pipe.

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.

# Thanks, S.C.

# 仅将 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.

#谢谢,SC

This may be what you want. If not, some other part of the ABSG should be able to help you, it is excellent.

这可能就是你想要的。如果没有,ABSG 的其他部分应该能够帮助你,它非常好。

回答by wilhelmtell

Take a look at named pipes:

看看命名管道:

$ mkfifo err
$ cmd1 2>err |cat - err |cmd2