linux - 'cat foo.txt | my_cmd' 和 'my_cmd < foo.txt' 完成同样的事情吗?

标签 linux bash redirect pipe stdin

This question帮助我理解重定向和管道之间的区别,但这些示例重点关注重定向 STDOUT ( echo foo > bar.txt ) 和管道 STDIN ( ls | grep foo )。

在我看来,任何命令都可以写成 my_command < file.txt也可以写成cat file.txt | my_command 。什么情况下需要 STDIN 重定向?

除了使用cat这一事实会产生额外的进程,并且比重定向 STDIN 效率低,是否存在必须使用 STDIN 重定向的情况?换句话说,是否有理由通过管道输出 cat到另一个命令?

最佳答案

my_command < file.txt 和有什么区别和cat file.txt | my_command

my_command < file.txt 

重定向符号也可以写成 0<因为这会将文件描述符 0 ( stdin ) 重定向到连接到 file.txt而不是当前设置,这可能是终端。如果my_command是一个内置的 shell,则不会创建子进程,否则会创建一个。

cat file.txt | my_command

这会将左侧命令的文件描述符 1 ( stdout ) 重定向到匿名管道的输入流,并将右侧命令的文件描述符 0 ( stdin ) 重定向到匿名管道的输出流管道。

我们立即看到有一个子进程,因为 cat不是内置的 shell。然而在 bash即使my_command是一个内置的 shell,它仍然在子进程中运行。因此我们有两个子进程。

因此,从理论上讲,管道的效率较低。这种差异是否显着取决于许多因素,包括“显着”的定义。管道更合适的时间是以下替代方案:

command1 > file.txt
command2 < file.txt

这里很可能

command1 | command2

效率更高,记住,在实践中,我们可能需要rm file.txt中的第三个子进程。 .

但是,管道也有限制。它们不可查找(随机访问,请参阅 man 2 lseek),并且不能内存映射(请参阅 man 2 mmap)。某些应用程序将文件映射到虚拟内存,但对 stdin 这样做是不寻常的。或stdout 。特别是内存映射在管道(无论是匿名还是命名)上是不可能的,因为必须保留一系列虚拟地址,并且需要一个大小。

编辑:

正如 @JohnKugelman 所提到的,许多 SO 问题的常见错误和根源是与子进程和重定向相关的问题:

获取文件file.txt有 99 行:

i=0
cat file.txt|while read
do
   (( i = i+1 ))
done

echo "$i"

显示什么?答案是0 。为什么?因为计数i = i + 1是在子shell中完成的,在bash中,是一个子进程,不会改变 i在父级中(注意:这不适用于 korn shell ksh )。

while read
do
   (( i = i+1 ))
done < file.txt

echo "$i"

这显示了正确的计数,因为不涉及子进程。

关于linux - 'cat foo.txt | my_cmd' 和 'my_cmd < foo.txt' 完成同样的事情吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48446896/

相关文章:

ruby - 如何在终端提示中显示 RVM 当前的 Ruby 和 gemset?

python - 重新连接期间的 getaddrinfo 行为

c - 具有自己的文件偏移量的重复文件描述符

linux - 允许特定 IP 的 MongoDB 远程访问

android - Httpclient 重定向处理程序

python - 进行重定向时如何传递模板值?

javascript - 使用 Node.js 和 Angular 重定向

linux - Bash 脚本问题

bash - 在 MOTD (Ubuntu) 中定义函数

linux - 通过 CGI 运行服务器端 Bash 脚本