我要取一个特定的行了一个大文件(150万线),在一个循环中在多个文件多次,我问我自己这将是最好的选择(在性能方面)。 有很多方法可以做到这一点,我男子气概使用这2个
cat ${file} | head -1
要么
cat ${file} | sed -n '1p'
我无法找到一个答案?他们都只有获取第一线或两个(或两个)的一个首先打开整个文件,然后读取该行1?
我要取一个特定的行了一个大文件(150万线),在一个循环中在多个文件多次,我问我自己这将是最好的选择(在性能方面)。 有很多方法可以做到这一点,我男子气概使用这2个
cat ${file} | head -1
要么
cat ${file} | sed -n '1p'
我无法找到一个答案?他们都只有获取第一线或两个(或两个)的一个首先打开整个文件,然后读取该行1?
删除无用的使用cat
做:
$ sed -n '1{p;q}' file
这将退出sed
行已被打印后的脚本。
标杆脚本:
#!/bin/bash
TIMEFORMAT='%3R'
n=25
heading=('head -1 file' 'sed -n 1p file' "sed -n '1{p;q} file" 'read line < file && echo $line')
# files upto a hundred million lines (if your on slow machine decrease!!)
for (( j=1; j<=100,000,000;j=j*10 ))
do
echo "Lines in file: $j"
# create file containing j lines
seq 1 $j > file
# initial read of file
cat file > /dev/null
for comm in {0..3}
do
avg=0
echo
echo ${heading[$comm]}
for (( i=1; i<=$n; i++ ))
do
case $comm in
0)
t=$( { time head -1 file > /dev/null; } 2>&1);;
1)
t=$( { time sed -n 1p file > /dev/null; } 2>&1);;
2)
t=$( { time sed '1{p;q}' file > /dev/null; } 2>&1);;
3)
t=$( { time read line < file && echo $line > /dev/null; } 2>&1);;
esac
avg=$avg+$t
done
echo "scale=3;($avg)/$n" | bc
done
done
只要保存为benchmark.sh
并运行bash benchmark.sh
。
结果:
head -1 file
.001
sed -n 1p file
.048
sed -n '1{p;q} file
.002
read line < file && echo $line
0
**从一个有1,000,000行的文件的结果。*
所以对于时间sed -n 1p
将与该文件的长度,但在其他变化的时机将是恒定的(可忽略不计),因为它们都看完第一行之后退出线性增长:
注意:定时由于是在一个更快的Linux机器是从原来的职位不同。
如果你真的刚开的第一行和读取数百个文件,然后再考虑shell内建命令,而不是外部的外部命令,使用read
这是内建的bash和ksh的壳。 这消除了进程创建与开销awk
, sed
, head
,等等。
另一个问题是在I / O做定时的性能分析。 当您第一次打开,然后读取文件,文件中的数据可能是不缓存在内存中。 但是,如果您再次尝试在同一文件中的第二个命令,数据以及索引节点已经被缓存,所以定时结果可能会更快,几乎无论你使用什么命令。 此外,索引节点可以保持实际上永远缓存。 它们例如做的Solaris。 或者反正几天。
例如,Linux的缓存一切和厨房水槽,这是一个很好的性能属性。 但它使,如果你不知道这个问题的基准问题。
所有这一切都缓存效应“干扰”既是操作系统和硬件相关。
所以 - 选择一个文件,用命令来读取它。 现在,它被缓存。 运行相同的测试指令数十倍,这是采样命令和子进程的创建,不是你的I / O硬件的作用。
这是sed VS读为得到相同的文件的第一行的10次迭代,读取文件后一次:
但是, sed '1{p;q}' uopgenl20121216.lis
real 0m0.917s
user 0m0.258s
sys 0m0.492s
读: read foo < uopgenl20121216.lis ; export foo; echo "$foo"
read foo < uopgenl20121216.lis ; export foo; echo "$foo"
real 0m0.017s
user 0m0.000s
sys 0m0.015s
这显然是人为的,但确实显示内置性能之间的差异VS使用命令。
如何避免管道? 双方sed
和head
支持文件名作为参数。 这样,你避免猫路过。 我没测,但头应该是较大的文件更快之后N行停止计算(而sed的通过所有的人都去,即使不打印出来-除非你指定q
的建议UIT选项以上)。
例子:
sed -n '1{p;q}' /path/to/file
head -n 1 /path/to/file
同样,我没有测试效率。
如果你只想打印1行(说20一个)从一个大的文件,你也可以这样做:
head -20 filename | tail -1
我没有使用bash“基本”试验,它似乎表现比更好sed -n '1{p;q}
溶液上方。
测试需要大文件,并且从中间的某个位置(在线打印一行10000000
),重复100次,每次选择下一行。 所以它选择行10000000,10000001,10000002, ...
等等,直到10000099
$wc -l english
36374448 english
$time for i in {0..99}; do j=$((i+10000000)); sed -n $j'{p;q}' english >/dev/null; done;
real 1m27.207s
user 1m20.712s
sys 0m6.284s
与
$time for i in {0..99}; do j=$((i+10000000)); head -$j english | tail -1 >/dev/null; done;
real 1m3.796s
user 0m59.356s
sys 0m32.376s
对于印刷线路输出的多个文件
$wc -l english*
36374448 english
17797377 english.1024MB
3461885 english.200MB
57633710 total
$time for i in english*; do sed -n '10000000{p;q}' $i >/dev/null; done;
real 0m2.059s
user 0m1.904s
sys 0m0.144s
$time for i in english*; do head -10000000 $i | tail -1 >/dev/null; done;
real 0m1.535s
user 0m1.420s
sys 0m0.788s