Bash:进程替换和标准输入


13

以下行很明显:

echo "bla" | foo | bar

但是下面的那些也一样吗?

echo "bla" | bar <(foo)
echo "bla" | bar < <(foo)

其中foo,并bar从标准,为什么读“喇嘛”?

我的意思是,我当然可以对其进行编码和检查,但是我不确定它是否是已定义的行为,或者我是否在利用我不应该依赖的功能。

Answers:


9

那是壳依赖的,没有文档AFAICS。在ksh和中bash,在第一种情况下,foo将与共享相同的stdin bar。他们将为的输出而战echo

例如,在

$ seq 10000 | paste - <(tr 1 X)'
1       X
2       X042
3       X043
4       X044
5       X045
[...]

您会看到证据,该证据pasteseq的输出中读取每个其他文本块,同时tr读取其他文本块。

使用zsh,它将获得外部标准输入(除非它是一个终端,并且外壳不是交互式的,在这种情况下,它是从重定向的/dev/null)。ksh(起源于此),zsh并且bash是唯一支持流程替换AFAIK的类Bourne外壳。

在中echo "bla" | bar < <(foo),请注意,barstdin将是的输出馈送的管道foo。这是定义明确的行为。在这种情况下,似乎foo的标准输入是通过供给管echo中的所有的kshzshbash

如果您希望在所有三个外壳上都具有一致的行为,并且要面向未来,因为该行为可能会因未记录而有所变化,请编写以下代码:

echo bla | { bar <(foo); }

为了确保foostdin也是管道echo(我看不出为什么要这么做)。要么:

echo bla | bar <(foo < /dev/null)

为了确保foo不会从管道中读取echo。要么:

{ echo bla | bar 3<&- <(foo <&3); } 3<&0

要拥有foo标准输入,如外部版本的标准输入一样zsh


“在那种情况下,foo的stdin是在所有ksh,zsh和bash中由echo提供的管道。” 您刚刚进行了手动测试,还是有记录?
etam1024

第一行中的“在第一种情况下”是否指的是`| |。foo | bar`或`| bar <(foo)`?
Volker Siegel 2014年

4

echo "bla" | foo | bar:的输出echo "bla"重定向到foo,其输出重定向到bar

echo "bla" | bar <(foo):将输出的管道echo "bla"传送到bar。但是bar用参数执行。参数是文件描述程序的路径,输出的文件foo将发送到该文件。此参数的行为类似于包含的输出的文件foo。所以,那是不一样的。

echo "bla" | bar < <(foo):可以假定echo "bla"应该将的输出发送到bar,并且整个语句与第一个语句等效。但是,这是不正确的。发生以下情况:由于输入重定向<是在管道(|)之后执行的,因此它将覆盖它。因此echo "bla"不通过管道传输到酒吧。而是将的输出foo重定向为的标准输入bar。要清除此错误,请参见以下命令和输出:

$ echo "bla" | cat < <(echo "foo")
foo

如您所见echo "bla"被取代echo "foo"

现在看到以下命令:

$ echo "bar" | cat < <(awk '{printf "%s and foo", $0}')
bar and foo

所以echo "bar"通过管道传递给awk,后者读取stdin并将字符串添加and foo到输出中。此输出通过管道传输到cat


我的问题是:“ awk读“条” 的事实是否是已定义的行为?”
etam1024

是的。cmd1 < <(cmd2)的行为与相同cmd2 | cmd1
混乱

还是cmd1 | cmd2 | cmd3等于cmd1 | cmd3 < <(cmd2)
混乱

3
如果是维基百科,我会在您的声明上加上“需要引用”标签:)我的问题的全部重点是,它可以按您所说的那样工作,但是我找不到任何有关它的文档。
etam1024 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.