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/