仅通过过滤器传输 STDERR
- 2024-10-18 09:00:00
- admin 原创
- 69
问题描述:
在 bash 中,有没有办法先将 STDERR 通过过滤器传输,然后再将其与 STDOUT 统一?也就是说,我想要
STDOUT ────────────────┐
├─────> terminal/file/whatever
STDERR ── [ filter ] ──┘
而不是
STDOUT ────┐
├────[ filter ]───> terminal/file/whatever
STDERR ────┘
解决方案 1:
总结:
$ 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)
>&2
将的STDOUTfilter
重定向回原始 STDERR。
解决方案 2:
下面是一个示例,模仿了如何在 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)
关闭 &3(&- 被欺骗为 3)
解决方案 3:
TL;DR:(bash 和 zsh)
$ cmd 2> >(stderr-filter >&2)
例子:
% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%
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
因此,鉴于这个假设和复杂的语法,您最好使用上面 TL;DR 中显示的更简单的bash
/语法,并在此处进行解释。zsh
实际演示,仅 grepping stderr:
$ ls -l . noexistABC noexistXYZ
ls: cannot access 'noexistABC': No such file or directory
ls: cannot access 'noexistXYZ': No such file or directory
.:
total 4
-rw-rw-r-- 1 frank frank 0 Aug 19 12:26 bar.txt
-rw-rw-r-- 1 frank frank 0 Aug 19 12:26 foo.txt
drwxrwxr-x 2 frank frank 4096 Aug 19 12:26 someFolder
$ ( ls -l . noexistABC noexistXYZ 2>&1 >&3 3>&- | grep ABC >&2 3>&-) 3>&1
.:
ls: cannot access 'noexistABC': No such file or directory
total 4
-rw-rw-r-- 1 frank frank 0 Aug 19 12:26 bar.txt
-rw-rw-r-- 1 frank frank 0 Aug 19 12:26 foo.txt
drwxrwxr-x 2 frank frank 4096 Aug 19 12:26 someFolder
解决方案 4:
简单使用进程替换似乎可以允许从中stderr
单独过滤stdout
:
:; ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 )
out
e:err
请注意,它会不断地出现stderr
,我们可以通过将整个内容包装在另一个子 shell 中并重定向到文件来看到它,stderr
`stdoutstdout
o`e
( ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) ) 1>o 2>e
解决方案 5:
我发现使用 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> 后面的空格是正确解析命令所必需的。
解决方案 6:
高级 Bash 脚本指南此页面的最后一部分是“仅将 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.
谢谢,SC
这也许就是你想要的。如果不是,ABSG 的其他部分应该能够帮助你,这非常好。
解决方案 7:
看一下命名管道:
$ mkfifo err
$ cmd1 2>err |cat - err |cmd2
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件