有没有一种 “规范” 的方式来做到这一点?我一直在使用head -n | tail -1
可以达到目的,但是我一直在想是否有一个 Bash 工具专门从文件中提取一行(或一系列行)。
“规范” 是指一个程序,其主要功能就是这样做。
head
, tail
大的文件会很慢。我建议sed
这样:
sed 'NUMq;d' file
其中NUM
是您要打印的行号;因此,例如, sed '10q;d' file
来打印第 10 行file
。
解释:
当行号为NUM
NUMq
将立即退出。
d
将删除该行而不是打印它;这在最后一行被禁止,因为q
导致退出时脚本的其余部分被跳过。
如果NUM
,则需要使用双引号而不是单引号:
sed "${NUM}q;d" file
sed -n '2p' < file.txt
将打印第二行
sed -n '2011p' < file.txt
第 2011 行
sed -n '10,33p' < file.txt
第 10 行到第 33 行
sed -n '1p;3p' < file.txt
第一和第三行
等等...
要添加带有 sed 的行,您可以检查以下内容:
我有一个独特的情况,可以在此页面上对提出的解决方案进行基准测试,因此我将这个答案写成对提出的解决方案的合并,其中包括每个解决方案的运行时间。
设置
我有一个 3.261 GB 的 ASCII 文本数据文件,每行有一个键值对。该文件总共包含 3,339,550,320 行,无法在我尝试过的任何编辑器(包括我的 Vim)中打开。我需要对该文件进行子集化,以调查我发现的某些值仅始于约 500,000,000 行。
由于文件有很多行:
我的最佳情况是一种解决方案,该解决方案仅从文件中提取一行而不读取文件中的任何其他行,但是我无法想到如何在 Bash 中完成此操作。
为了我的理智,我不会尝试读取我自己的问题所需的全部 500,000,000 行。相反,我将尝试从 3,339,550,320 中提取行 50,000,000(这意味着读取完整文件将比需要的时间长 60 倍)。
我将使用time
对每个命令进行基准测试。
基准线
首先,让我们看看如何在head
tail
的解决方案:
$ time head -50000000 myfile.ascii | tail -1
pgm_icnt = 0
real 1m15.321s
5000 万行的基准时间是 00:01:15.321,如果我直接进入 5 亿行,则可能需要 12.5 分钟左右的时间。
切
我对此表示怀疑,但值得一试:
$ time cut -f50000000 -d$'\n' myfile.ascii
pgm_icnt = 0
real 5m12.156s
这需要 00:05:12.156 来运行,这比基线要慢得多!我不确定在停止之前它是读取整个文件还是读取 5000 万行,但是无论如何这似乎都不是解决该问题的可行方法。
AWK
exit
运行该解决方案,因为我不想等待完整文件运行:
$ time awk 'NR == 50000000 {print; exit}' myfile.ascii
pgm_icnt = 0
real 1m16.583s
这段代码在 00:01:16.583 中运行,仅慢了约 1 秒,但仍然没有改善基线。以这种速度,如果排除了退出命令,则可能要花费大约 76 分钟才能读取整个文件!
佩尔
我还运行了现有的 Perl 解决方案:
$ time perl -wnl -e '$.== 50000000 && print && exit;' myfile.ascii
pgm_icnt = 0
real 1m13.146s
这段代码在 00:01:13.146 中运行,比基准速度快约 2 秒。如果我以全部 500,000,000 的价格运行它,则可能需要约 12 分钟。
sed
董事会最重要的答案是我的结果:
$ time sed "50000000q;d" myfile.ascii
pgm_icnt = 0
real 1m12.705s
这段代码在 00:01:12.705 运行,比基线快 3 秒,比 Perl 快〜0.4 秒。如果我在全部 500,000,000 行上运行它,则可能要花费大约 12 分钟。
映射文件
我有 bash 3.1,因此无法测试 mapfile 解决方案。
结论
在大多数情况下,看起来很难在head
tail
解决方案上进行改进。最好的sed
解决方案可将效率提高约 3%。
(使用公式% = (runtime/baseline - 1) * 100
计算的百分比)
第 50,000,000 行
sed
perl
head|tail
awk
cut
第 500,000,000 行
sed
perl
head|tail
awk
cut
第 3,338,559,320 行
sed
perl
head|tail
awk
cut