使用 'head' 和 'tail' 从 cat 输出中读取 'first and last line' 时出现奇怪的结果
Strange result while perform reading 'first and last line' from cat output with 'head' and 'tail'
Bash 版本 4.4.7.
来自 tutorial,获取文件的第一行和最后一行:
cat txt_file | (head -n1 && tail -n1)
但是,对于大文件(我不知道这会有多大,但文件有大约几千行)这个命令运行良好,但对于小文件,例如:
11111111
22222222
33333333
44444444
about命令的输出只有第一行:
11111111
另一个命令,使用 awk,适用于两个文件:
awk 'NR==1; END{print}'
你现在的"question"实际上并不是一个问题,它只是一个观察。然而,要解释你的观察。考虑输出之间的差异:
$ seq 10 | (head -1 && tail -1)
1
和
$ seq 1000 | (head -1 && tail -1)
1
1000
这里发生了什么?我们的管道工作如下:
- 将行(在本例中为数字,但与您的
cat
示例没有区别)发送到标准输出;
读取标准输出我们有:
- 首先,一个
head
...它会打印第一行然后结束;
- 接下来,一个
tail
... 它将在 之后 开始 运行 并打印最后一行。
但是,默认情况下,head
不是逐行读取文件,甚至是逐字符读取直到找到换行符,而是读取文件文件块(缓冲读取)。例如,该块可能是 2048 字节。
所以我们的管道真的是:
- 将行(在本例中为数字,但与您的
cat
示例没有区别)发送到标准输出;
读取标准输出我们有:
- 首先,一个
head
...它将从标准输入读取前2kb,打印第一行然后结束;
- 接下来,
tail
...它将读取第一个 2k 之后的剩余数据 ,因为它从未看到它。
如果您的目标是只生成一次第一个命令(您的 cat
)的输出,那么您可以使用 tee
,可能是这样的:
$ seq 10 | tee >(tail -1) | head -2
另请注意,在 linux 上,您可以更改第一个命令的缓冲,例如:
$ stdbuf -oL seq 10 | (head -1 && tail -1)
但如果您的命令摆弄其流(请参阅 stdbuf),这将不起作用
也尝试以下操作:
sed解决方案:
sed -n '1p;$p' <(seq 1000)
perl解决方案:
seq 100 | perl -ne 'print if 1..1 or eof'
bash 只有尾巴的解决方案:
seq 100 | { IFS= read -r line; echo "$line"; tail -1; }
Bash 版本 4.4.7.
来自 tutorial,获取文件的第一行和最后一行:
cat txt_file | (head -n1 && tail -n1)
但是,对于大文件(我不知道这会有多大,但文件有大约几千行)这个命令运行良好,但对于小文件,例如:
11111111
22222222
33333333
44444444
about命令的输出只有第一行:
11111111
另一个命令,使用 awk,适用于两个文件:
awk 'NR==1; END{print}'
你现在的"question"实际上并不是一个问题,它只是一个观察。然而,要解释你的观察。考虑输出之间的差异:
$ seq 10 | (head -1 && tail -1)
1
和
$ seq 1000 | (head -1 && tail -1)
1
1000
这里发生了什么?我们的管道工作如下:
- 将行(在本例中为数字,但与您的
cat
示例没有区别)发送到标准输出; 读取标准输出我们有:
- 首先,一个
head
...它会打印第一行然后结束; - 接下来,一个
tail
... 它将在 之后 开始 运行 并打印最后一行。
- 首先,一个
但是,默认情况下,head
不是逐行读取文件,甚至是逐字符读取直到找到换行符,而是读取文件文件块(缓冲读取)。例如,该块可能是 2048 字节。
所以我们的管道真的是:
- 将行(在本例中为数字,但与您的
cat
示例没有区别)发送到标准输出; 读取标准输出我们有:
- 首先,一个
head
...它将从标准输入读取前2kb,打印第一行然后结束; - 接下来,
tail
...它将读取第一个 2k 之后的剩余数据 ,因为它从未看到它。
- 首先,一个
如果您的目标是只生成一次第一个命令(您的 cat
)的输出,那么您可以使用 tee
,可能是这样的:
$ seq 10 | tee >(tail -1) | head -2
另请注意,在 linux 上,您可以更改第一个命令的缓冲,例如:
$ stdbuf -oL seq 10 | (head -1 && tail -1)
但如果您的命令摆弄其流(请参阅 stdbuf),这将不起作用
也尝试以下操作: sed解决方案:
sed -n '1p;$p' <(seq 1000)
perl解决方案:
seq 100 | perl -ne 'print if 1..1 or eof'
bash 只有尾巴的解决方案:
seq 100 | { IFS= read -r line; echo "$line"; tail -1; }