Bash:进程替换和标准输入

Bash:进程替换和标准输入

下面这行是显而易见的:

echo "bla" | foo | bar

但下面的人也这样做吗?

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

哪个和从标准输入读取“bla”,为什么foobar

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

答案1

这是依赖于 shell 的,并且没有记录在案的 AFAICS。在ksh和 中bash,在第一种情况下,foo将与 共享相同的标准输入bar。他们将为输出而战echo

例如,

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

您会看到从的输出paste中读取每隔一个文本块的证据,同时读取其他文本块。seqtr

使用zsh,它获取外部标准输入(除非它是终端并且 shell 不是交互式的,在这种情况下它会从/dev/null中重定向cmd &)。ksh(它的起源),zsh并且bash是唯一支持进程替换的类 Bourne shell。

在 中echo "bla" | bar < <(foo),请注意,bar的 stdin 将是由 的输出提供的管道foo。这是明确定义的行为。在这种情况下,看起来的 stdin 是所有,和中foo提供的管道。echokshzshbash

如果您希望在所有三个 shell 中具有一致的行为,并且能够面向未来,因为行为可能会因未记录而发生变化,我会这样写:

echo bla | { bar <(foo); }

可以肯定的是foo, 的 stdin 也是来自的管道echo(但我不明白你为什么要这样做)。或者:

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

foo为了确保不是从管道中读取echo。或者:

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

foo's stdin 成为外部标准输入,就像当前版本的zsh.

答案2

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

Soecho "bar"通过管道传输到awk,它读取 stdin 并将字符串添加and foo到输出中。该输出通过管道传输到cat.

相关内容