Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/google-maps/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 为什么从文件中获取stdin与通过管道接收stdin不同?_Bash_Unix_Pipe - Fatal编程技术网

Bash 为什么从文件中获取stdin与通过管道接收stdin不同?

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然后

使用bash,我通常希望获得一个大型csv文件的标题,并在其余部分搜索特定条目。我是这样做的

$ (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
,而不是bash
head
将读取缓冲区并找到适当的行数,然后
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