sha*_*ant 7 bash pipe io-redirection file-descriptors process-substitution
$ echo 123 | cat
123
Run Code Online (Sandbox Code Playgroud)
正在做我所期望的,两个命令都在同一个 shell 中运行。
但是,当我将它们与>( ... )表达式连接起来时,该表达式将 shell 中的一个命令的输出连接到子 shell 中的第二个命令,我得到了这个:
$ echo 123 >(cat)
123 /dev/fd/63
Run Code Online (Sandbox Code Playgroud)
对于其他值也是如此:
$ echo 101 >(cat)
101 /dev/fd/63
$ echo $BASHPID >(cat)
3252 /dev/fd/63
Run Code Online (Sandbox Code Playgroud)
我认为command1 >(command2)与 相同command1 | command2,但是在 中command1 >(command2),每个命令都在不同的 shell 中,因此它们应该具有相同的输出。我哪里错了?
Kus*_*nda 11
进程替换>(thing)将被文件名替换。此文件名对应于连接到thing内部替换的标准输入的文件。
以下将是其使用的更好示例:
$ sort -o >(cat -n >/tmp/out) ~/.profile
Run Code Online (Sandbox Code Playgroud)
这将对文件进行排序~/.profile并将输出发送到cat -n枚举行并将结果存储在/tmp/out.
所以,回答你的问题:你得到那个输出是因为echo得到了两个参数123和/dev/fd/63。 /dev/fd/63是cat在进程替换中连接到进程标准输入的文件。
稍微修改您的示例代码:
$ echo 101 > >(cat)
Run Code Online (Sandbox Code Playgroud)
这将仅101在标准输出上产生( 的输出echo将被重定向到作为 输入的文件cat,并将cat在标准输出上产生该文件的内容)。
另请注意,在cmd1 | cmd2管道中,cmd2可能根本不在同一 shell 中运行cmd1(取决于您使用的 shell 实现)。 ksh93以您描述的方式工作(相同的外壳),同时为其bash创建一个子外壳cmd2(除非lastpipe设置了它的外壳选项并且作业控制未处于活动状态)。
为了完整性
cmd1 >(cmd2)
Run Code Online (Sandbox Code Playgroud)
大部分是一样的
cmd1 | cmd2
Run Code Online (Sandbox Code Playgroud)
在yash壳中,只有那个壳。
在该外壳,>(cmd)是处理重定向而不是在>(cmd)的ksh/ bash/zsh其是过程替代。
它不是严格等价的,因为 in cmd1 >(cmd2),yash不等待cmd2,所以你可能会发现:
$ yash -c 'echo A >(cat); echo B'
B
A
$ yash -c 'echo A | cat; echo B'
A
B
Run Code Online (Sandbox Code Playgroud)
相比之下,处理置换扩展到一个文件路径(通常是命名管道或/dev/fd/<x>其中<x>是一个FD到已预先创建的配管),其在打开时用于写入将允许将输出发送到cmd。
虽然进程替换是由 引入的ksh,但在该 shell 中,您不能将它们作为参数传递给重定向。
ksh -c 'cmd1 > >(cmd2)'
Run Code Online (Sandbox Code Playgroud)
模拟yash进程重定向将不起作用。在那里,您打算将替换产生的文件名作为参数传递给如下命令:
ksh -c 'diff <(echo a) <(echo b)'
Run Code Online (Sandbox Code Playgroud)
它将在bash和 中工作zsh。
但是,bash就像 foryash的进程重定向一样,shell 不会等待命令 ( cmd2)。所以:
$ bash -c 'echo A > >(cat); echo B'
B
A
Run Code Online (Sandbox Code Playgroud)
ksh可以使用以下方法模拟进程替换yash:
cmd1 /dev/fd/5 5>(cmd2)
Run Code Online (Sandbox Code Playgroud)
喜欢:
diff /dev/fd/3 3<(echo a) /dev/fd/4 4<(echo b)
Run Code Online (Sandbox Code Playgroud)
因为这就是进程替换所做的,它使替换中的命令显示为文件名。在内部,它通过管道连接命令,提供/dev/fd/NN主命令的路径,因此它可以将已经打开的文件描述符打开到管道。
它与管道不同。管道连接stdout到stdin不涉及任何看起来像文件名的东西。进程替换更加灵活,因为您可以在一个命令行中进行多个这样的替换,但它需要主命令按名称打开文件(例如,cat而不是echo)。
您可以通过执行以下操作来模拟带有进程替换的管道:
echo foo > >(cat -n)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6552 次 |
| 最近记录: |