如果只需要第一行或第二行,则可以使用以下类型的技巧,并且可以避免由于使用两个不同的命令读取输出流而导致的缓冲问题:
$ ps -eF | { IFS= read -r x ; echo "$x" ; grep worker; }
$ ls -la / | { IFS= read -r x ; echo "$x" ; grep sbin; }
的read
是内置于壳和不消耗输入的整个缓冲器只是输出一行,因此,使用read
叶片的输出的所有其余为以下命令。
如果要强调使用两个不同命令的示例所显示的缓冲问题,请sleep
在其上添加a 以消除计时问题,并允许左侧的命令生成所有输出,然后右侧的命令尝试读取任何内容。它:
$ ps -eF | { sleep 5 ; head -n 1 ; grep worker; }
$ ls -la / | { sleep 5 ; head -n 1 ; grep sbin; }
现在,以上两个示例均以相同的方式失败- head
读取输出的整个缓冲区只是产生一行,而该缓冲区对以下对象不可用grep
。
通过使用一些对输出行编号的示例,您可以更清楚地看到缓冲问题,从而可以知道缺少哪些行:
$ ps -eF | cat -n | { sleep 5 ; head -n 1 ; head ; }
$ ls -la /usr/bin | cat -n | { sleep 5 ; head -n 1 ; head ; }
解决缓冲问题的一种简单方法是使用seq
生成数字列表。我们可以轻松判断出哪些数字丢失了:
$ seq 1 100000 | { sleep 5 ; head -n 1 ; head ; }
1
1861
1862
1863
1864
1865
1866
1867
1868
1869
我的技巧解决方案使用Shell读取并回显第一行,即使添加了睡眠延迟,也可以正常工作:
$ seq 1 100000 | { sleep 5 ; IFS= read -r x ; echo "$x" ; head ; }
1
2
3
4
5
6
7
8
9
10
11
下面是显示head
缓冲问题的完整示例,显示了如何
head
消耗输出的整个缓冲区,而每次仅产生其五行。该消耗的缓冲区不适用于head
序列中的下一个
命令:
$ seq 1 100000 | { sleep 5 ; head -5 ; head -5 ; head -5 ; head -5 ; }
1
2
3
4
5
1861
1862
1863
1864
499
3500
3501
3502
3503
7
5138
5139
5140
5141
查看1861
上面的数字,我们可以head
通过计算to 的seq
输出1
来
计算正在使用的缓冲区的大小1860
:
$ seq 1 1860 | wc -c
8193
我们看到,head
通过一次读取完整的8KB(8 * 1024字节)的管道输出来缓冲,甚至只产生几行自己的输出。
head
和grep
做什么也没有。