我试图了解是什么导致了我认为在功能上等效的这两个构造的差异:
$ ( echo foo >&2 ) 2> >(sed 's/^/stderr: /') | sed 's/^/stdout: /'
stdout: stderr: foo
$ ( echo foo >&2 ) 2> >(sed 's/^/stderr: /') > >(sed 's/^/stdout: /')
stderr: foo
编辑:如果我理解 user1133275 正确,他建议>(sed 's/^/stdout: /')
不要运行,除非子外壳( echo foo >&2 )
输出到标准输出。但是,这将意味着以下内容:
$ ( echo foo >&2 ) 2> >(sed 's/^/stderr: /') > >(echo baz)
baz
stderr: foo
不应该显示baz
。
编辑 2:也许也很有趣, sed 不会stdout:
在空输入上输出,即使是通过管道传输的:
$ sed 's/^/stdout: /' < /dev/null
$ printf "" | sed 's/^/stdout: /'
$
你的第一个命令,
以简化形式(使用临时文件保存由 生成的数据
echo
):即,第一个
sed
读取从标准错误产生的内容echo
并写入标准输出,第二个sed
读取并修改它。你的第二个命令,
以简化的形式,
在这里,
sed
获得标准错误输出的那个产生输出,而另一个sed
获得标准输出输出(什么都没有)的那个不产生任何输出(因为它没有得到任何输入并且因为它没有插入或附加任何数据) .另一种表述方式:
第一个命令:
第二条命令:
简而言之,第二
sed
个命令中的第二个从不读取任何内容。特别是,它不像第sed
一个命令那样从第一个命令中读取输出。使用极其简化的符号,第一个命令类似于
where
something1
写入标准输出,由something2
.第二个命令,使用相同的符号,
即
something1
,something2
甚至没有相互连接,并且something2
无法以任何方式读取something1
正在产生的内容。此外,由于utility-writing-to-stderr
不会在其标准输出流上产生任何内容,something2
因此不会从其标准输入中读取任何内容。>
由于 shell 中的重定向顺序,正在运行( echo foo >&2 )
并且|
正在运行。>(sed 's/^/stderr: /')
例如或者
vs 明确的例子问题中的顺序
或者
这两个命令是不等价的。
命令(1):
将 (std) 输出发送
two
到three
(更多关于 stderr 下面)。命令(2):
将 (std) 输出发送
one
到three
(stderr go totwo
)。痛苦的细节是:
命令 1:
( one ) 2> >(two) | three
three
已启动 (sed 's/^/stdout: /'
) 等待标准输入上的输入。2
将(stderr
)重定向到stdin
oftwo
。one
(echo foo >&2
)。foo
到stderr
(没有到标准输出)。foo
重定向到 ( of )。stderr
one
stdin
two
sed 's/^/stderr: /'
)two
( )现在修改后的输出stderr: foo
被发送到 的标准输出two
。two
通过管道传输到three
.three
从一开始就等待输入的命令得到输出。stdout:
。stdout: stderr: foo
转到 tty。命令2:(一)2>>(二)>>(三)
>
) 首先构建。three
上开始等待输入。stdin
>()
three
获取.one
two
开始等待输入。two
(仅)获取one
.one
到其stderr
.one
被执行发送foo
到stderr
(ofone
)。foo
去two
two
更改接收到的字符串stderr: foo
并将其发送到tty。three
从 的标准输出接收一个空输入one
。three
什么都不打印(因为没有要处理的行)。理解这个命令:
没有输出(也没有办法让它工作)。
更改顺序:命令 3:(一)>>(三)2>>(二)
two
将go tothree
(而不是)详细信息的输出留作tty
练习。我赞成@Kusalananda 非常明确的答案,但我冒险(迟来)将其添加到他的答案中,作为工作中流程替换的一个小例子:
您的第二个命题将适用于一个小的印刷变化(及其错误逻辑的相对较大的变化):
但:
因为
( )>
如图所示添加(或者>( )
,两者都可以正常工作)实际上允许您通过进程替换创建一个文件,其输出可以作为输入重定向到>(sed 's/^/stdout: /')
.我考虑添加这个来说明如何将流程替换嵌入到另一个流程替换中。为了可读性,我不会将其推向更多嵌入级别。但是如果出于任何原因您需要避免使用管道和相关的shell,这是一个很好的解决方案。