Bash 为什么从文件中获取stdin与通过管道接收stdin不同?
使用bash,我通常希望获得一个大型csv文件的标题,并在其余部分搜索特定条目。我是这样做的Bash 为什么从文件中获取stdin与通过管道接收stdin不同?,bash,unix,pipe,Bash,Unix,Pipe,使用bash,我通常希望获得一个大型csv文件的标题,并在其余部分搜索特定条目。我是这样做的 $ (head -1; grep mike) < tmp.csv name,age,favourite colour mike,38,blue 为什么在这两种情况下会有不同的行为?我无法用bash 3.2.48可靠地再现这一点。要么都成功,要么都失败。但是失败的根本原因是文件有多大 cat读取一个缓冲区(4k-64k,具体取决于系统),然后将其交给管道head消耗整个缓冲区,然后退出grep然后
$ (head -1; grep mike) < tmp.csv
name,age,favourite colour
mike,38,blue
为什么在这两种情况下会有不同的行为?我无法用bash 3.2.48可靠地再现这一点。要么都成功,要么都失败。但是失败的根本原因是文件有多大
cat
读取一个缓冲区(4k-64k,具体取决于系统),然后将其交给管道head
消耗整个缓冲区,然后退出grep
然后在缓冲区大小之后可以访问该文件。在我的系统中,我只能使用你的管道将grep
东西进一步放入文件中的一个缓冲区(因此我可以grep
东西放在长文件的末尾,但在使用head
后不能放在开头)
bash的更高版本可能会对
进行优化,这非常奇怪。您不应该依赖这种未记录的行为,而是使用类似的方式:
sed -n '1p;/mike/p' tmp.csv
从管道读取和从文件读取的区别在于,可以对文件执行lseek
,但不能对管道执行
这里的行为看起来(通过strace
)像是来自head
,而不是bashhead
将读取缓冲区并找到适当的行数,然后lseek
向后返回到最后一个输出行结束的位置,使文件句柄在该位置保持打开状态。如上所述,如果它正在读取一个文件,则此操作有效,但如果它正在从管道中读取,则此操作无效
除了你在做什么,我想不出任何情况下,head
中的这种行为是有意义的,但它确实存在。我告诉你,每天都要学习新的东西…wc-l test.txt
-output->3(head-1>/dev/null;wc-l)
-outupt->2!我有一些理论,但我无法用Bash3.2.48(达尔文)重现。您使用的是哪个版本?这是GNU bash,版本3.2.25(1)-在rhel 5.6机器上发布(x86_64-redhat-linux-GNU)。这不是未记录的行为。一切正常(见邪恶的奥托斯回答)。使用(command1;command2)
构造从公共标准输入读取数据是一种糟糕的做法,因为第二个标准输入取决于第一个标准输入的行为。所以你的命令也是对的。
sed -n '1p;/mike/p' tmp.csv