Skip to content

Linux 如何在命令行中输出大文件中的一小段

遇到一个场景, 对于一个大文件, 输出其中的小部分行, 在网上找到了解决方案, 发现有好几种, 时间各不相同, 于是记录一下自己的看法.

参考: https://unix.stackexchange.com/questions/47407/cat-line-x-to-line-y-on-a-huge-file

假如输出 X 到 Y 行, 有这几种方式

awk "NR >= X && NR <= Y" /path/to/file
tail -n "+$X" /path/to/file | head -n "$((Y-X+1))"
head -n "+$Y" /path/to/file | tail -n "$((X))"
sed -n -e 'X,Y p' -e 'Y q' /tmp/a

上面的网站说第二种是最快的, 这个让我感到很困惑, 第二/三种方法按理来说 tail 前的所有内容都会传入到 head 中, 应该很浪费时间, 而第四种方法中利用了 sed 的指定特定行的特点, 不应该很快吗.

解释如下.
1. 找到文件的某一行没有专门的方法, 只有遍历, 通过有多少 '\n' 来实现. 以前在汇编和 C 语言中有文件指针偏移, 但是那个是偏移字节数, 偏移行数确实是无法立刻完成的. 所以 sed 中的指定行其实也是需要遍历的.

2. 第二种方法中 tail 会从后往前扫, 除了前 X 行不会扫到; 然后 head 从前往后扫, 会扫 (Y-X) 行. 加入文件一共 N 行, 那么扫过的内容为 (N-X) + (Y-X), 也就是从 X 往后的行数 加上 X 到 Y 的行数.

3. 第三种方法一共是 (Y) + (Y-X), 也就是从 Y 往前的行数 加上 X 到 Y 行数

4. 第四种方法中 sed 就会一直往后扫, 内容是从 Y 往前的行数.

5. 所以可以看第三种方法和第四种就差了 X 到 Y 之间内容, 而这里面内容很少, 所以可以忽略不计. 而我猜测 headtail 应该是有比较很好的优化, 所以相比 sed 就快了一些. 如果 X 到 Y 内容很大, 我猜测可能 sed 会快一点.

Comments