澄清我之前的评论。我将展示一个简单的可重现样本:
linelist内容:
10
15858
14
1499
为了模拟长输入,我将使用seq -w 100000000.
将 sed 解决方案与我的建议进行比较,我们有:
#!/bin/bash
time (
sed 's/$/p/' linelist > selector
seq -w 100000000 | sed -nf selector
)
time (
sort -n linelist | sed '$!{s/$/p/};$s/$/{p;q}/' > my_selector
seq -w 100000000 | sed -nf my_selector
)
输出:
000000010
000000014
000001499
000015858
real 1m23.375s
user 1m38.004s
sys 0m1.337s
000000010
000000014
000001499
000015858
real 0m0.013s
user 0m0.014s
sys 0m0.002s
将我的解决方案与 awk 进行比较:
#!/bin/bash
time (
awk '
# process first file
FNR==NR { nums[$1]
maxFNR= ($1>maxFNR ? $1 : maxFNR)
next
}
# process subsequent file(s):
FNR > maxFNR { exit }
FNR in nums
' linelist <(seq -w 100000000)
)
time (
sort -n linelist | sed '$!{s/$/p/};$s/$/{p;q}/' > my_selector
sed -nf my_selector <(seq -w 100000000)
)
输出:
000000010
000000014
000001499
000015858
real 0m0.023s
user 0m0.020s
sys 0m0.001s
000000010
000000014
000001499
000015858
real 0m0.017s
user 0m0.007s
sys 0m0.001s
在我的结论中,seq使用q与awk解决方案相当。为了可读性和可维护性,我更喜欢awk解决方案。
无论如何,这个测试很简单,只对小的比较有用。例如,我不知道如果我用大量磁盘 I/O 对真正的压缩文件进行测试,结果会怎样。
埃德莫顿编辑:
任何导致所有输出值小于一秒的速度测试都是不好的测试,因为:
- 一般来说,没有人关心 X 是在 0.1 秒还是 0.2 秒内运行,除非在大循环中调用它们,否则它们都足够快,并且
- 缓存之类的事情会影响结果,并且
- 通常,对于执行速度无关紧要的小输入集运行较快的脚本对于执行速度确实重要的大输入集运行较慢(例如,如果对于小输入较慢的脚本花费时间设置将让它运行得更快)
上面示例的问题是它只尝试打印 4 行而不是 OP 说他们必须选择的 1000 行,因此它不会影响 sed 和导致 sed 解决方案的 awk 解决方案之间的差异比 awk 慢得多,因为 sed 解决方案必须测试每一行输入的每个目标行号,而 awk 解决方案只对当前行进行一次哈希查找。这是输入文件每一行的 order(N) vs order(1) 算法。
这是一个更好的示例,显示从 1000000 行文件中每 100 行打印一次(即将选择 1000 行),而不是从任何大小的文件中仅打印 4 行:
$ cat tst_awk.sh
#!/usr/bin/env bash
n=1000000
m=100
awk -v n="$n" -v m="$m" 'BEGIN{for (i=1; i<=n; i+=m) print i}' > linelist
seq "$n" |
awk '
FNR==NR {
nums[$1]
maxFNR = $1
next
}
FNR in nums {
print
if ( FNR == maxFNR ) {
exit
}
}
' linelist -
$ cat tst_sed.sh
#!/usr/bin/env bash
n=1000000
m=100
awk -v n="$n" -v m="$m" 'BEGIN{for (i=1; i<=n; i+=m) print i}' > linelist
sed '$!{s/$/p/};$s/$/{p;q}/' linelist > my_selector
seq "$n" |
sed -nf my_selector
$ time ./tst_awk.sh > ou.awk
real 0m0.376s
user 0m0.311s
sys 0m0.061s
$ time ./tst_sed.sh > ou.sed
real 0m33.757s
user 0m33.576s
sys 0m0.045s
如您所见,awk 解决方案的运行速度比 sed 解决方案快 2 个数量级,并且它们产生了相同的输出:
$ diff ou.awk ou.sed
$
如果我使输入文件更大并通过设置从中选择 10,000 行:
n=10000000
m=1000
在每个脚本中,这对于 OP 的使用可能变得更加现实,差异变得非常令人印象深刻:
$ time ./tst_awk.sh > ou.awk
real 0m2.474s
user 0m2.843s
sys 0m0.122s
$ time ./tst_sed.sh > ou.sed
real 5m31.539s
user 5m31.669s
sys 0m0.183s
即 awk 运行时间为 2.5 秒,而 sed 运行时间为 5.5 分钟!