我试图运行下面给出的命令
cat numbers.txt | sort < words.txt
上面的命令有一个从 cat 命令馈送到 sort 命令输入流的管道。但同时,sort命令的输入流也被重定向到words.txt文件。运行命令时,我发现words.txt 中的数据已按排序命令排序并显示回终端中。
我不明白在这种情况下外壳程序如何处理管道和重定向。一个命令是否可以接受来自两个不同源的输入流。我对其内部工作方式的想法是,由于重定向和管道是沿着命令从左到右处理的,因此首先将 cat 命令的输出流作为 sort 命令的输入流。但由于排序命令在该管道之后提供了另一个输入流重定向,因此排序命令的输入流将连接到words.txt。因此,当命令执行时,words.txt 中的数据只会到达排序命令。
另外为什么下面的命令不运行。我已经通过覆盖更改了重定向,通过附加重定向。
cat numbers.txt | sort << words.txt
有一个问题部分与此类似,但我无法完全理解外壳程序如何处理管道和重定向。
答案1
重定向是从左到右处理的,并且在 Bash 中,在管道之后(事实上,在任何 POSIX shell)。在
cat numbers.txt | sort < words.txt
shell 首先将sort
的(未来)标准输入设置为来自 的管道cat
,但随后在处理时< words.txt
将其更改为读取words.txt
。
<<
启动一个定界符:
cat numbers.txt | sort << words.txt
将等待一行显示“words.txt”(因为这是命令中指定为输入结束标记)。请参阅shell 的控制和重定向运算符是什么?
答案2
一个命令是否可以接受来自两个不同源的输入流。
不;输入流实际上只是其他人交给您的文件描述符。正如一个文件中只有一个文件一样,无法合并多个流。
cat numbers.txt | sort < words.txt
顺便说一句,cat
是 con enate 的缩写cat
;从字面上看,它的工作是将命令行上指定的所有文件连接到其输出流:
cat numbers.txt words.txt | sort
作品。当然,sort
它本身也可以对多个文件进行排序,所以sort numbers.txt words.txt
效果也一样。
但我想这个问题更普遍:
如果我有多个文件和流,如何将它们连接成一个输出?
嗯,现代 shell 确实可以满足您的需求(至少 bash 和 zsh 可以):
cat file1 <(some program that generates output) <(echo "foo bar") file2 | sort
这些 shell 具有<(…)
,即“生成一个作为输入文件名传递的临时管道”。当然,还有非常简单的子shell方法:
( cat file1; some program that generates output; echo "foo bar"; cat file2 ) | sort
具有相同的效果。 (那里是执行并行度的差异;cat <(sleep 2; echo hello) <(sleep 2; echo world)
总共需要2秒执行;(sleep 2; echo hello; sleep 2; echo world)
需要 4 秒。)