在文件中打印单行的最快方法

JBo*_*Boy 14 bash benchmarking sed head cat

我必须从一个大文件(1500000行)中获取一个特定的行,在多个文件的循环中多次,我问自己什么是最好的选择(在性能方面).有很多方法可以做到这一点,我男子气概使用这些2

cat ${file} | head -1
Run Code Online (Sandbox Code Playgroud)

要么

cat ${file} | sed -n '1p'
Run Code Online (Sandbox Code Playgroud)

我找不到这个问题的答案,他们只获取第一行或两者之一(或两者)首先打开整个文件,然后获取第1行?

Chr*_*our 30

放弃无用的使用cat并做:

$ sed -n '1{p;q}' file
Run Code Online (Sandbox Code Playgroud)

这将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
Run Code Online (Sandbox Code Playgroud)

只需保存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
Run Code Online (Sandbox Code Playgroud)

**来自1,000,000行的文件结果.*

因此,时间sed -n 1p将与文件的长度成线性增长,但其他变化的时间将是恒定的(并且可以忽略不计),因为它们在读取第一行后都退出:

在此输入图像描述

注意:由于在更快的Linux机器上,时间与原始帖子不同.

  • 或者也许是`sed 1q file`,这有点不那么忙. (3认同)

jim*_*ara 5

如果你真的只是获得第一行并阅读数百个文件,那么考虑使用shell内置而不是外部外部命令,使用read内置用于bash和ksh的shell.这消除了进程创建的开销awk,sed,head,等.

另一个问题是对I/O进行定时性能分析.第一次打开然后读取文件时,文件数据可能没有缓存在内存中.但是,如果再次对同一文件尝试第二个命令,则数据和inode都已缓存,因此定时结果可能更快,几乎与您使用的命令无关.此外,inode可以保持几乎永远缓存.例如,它们在Solaris上运行.或者无论如何,好几天.

例如,linux缓存所有东西和厨房水槽,这是一个很好的性能属性.但如果您不了解这个问题,它会使基准测试成为问题.

所有这些缓存效果"干扰"都取决于操作系统和硬件.

所以 - 选择一个文件,用命令读取.现在它被缓存了.运行相同的测试命令几十次,这是对命令和子进程创建的效果进行采样,而不是I/O硬件.

在读取文件一次之后,这是获取同一文件的第一行的10次迭代的sed vs读取:

SED: sed '1{p;q}' uopgenl20121216.lis

real    0m0.917s
user    0m0.258s
sys     0m0.492s
Run Code Online (Sandbox Code Playgroud)

读: read foo < uopgenl20121216.lis ; export foo; echo "$foo"

real    0m0.017s
user    0m0.000s
sys     0m0.015s
Run Code Online (Sandbox Code Playgroud)

这显然是做作的,但确实显示了内置性能与使用命令之间的区别.


dvv*_*vrt 5

如果你只想从一个大文件中打印 1 行(比如第 20 行),你也可以这样做:

head -20 filename | tail -1
Run Code Online (Sandbox Code Playgroud)

我用 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
Run Code Online (Sandbox Code Playgroud)

$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
Run Code Online (Sandbox Code Playgroud)

用于从多个文件中打印一行

$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
Run Code Online (Sandbox Code Playgroud)