如何从文件中获取特定行?

Emi*_*lás 10 text-processing files

我想从一个非常大的文件中提取精确的行。例如,第 8000 行会像这样得到:

command -line 8000 > output_line_8000.txt
Run Code Online (Sandbox Code Playgroud)

gni*_*urf 14

perl和已经有答案了awk。这是一个sed答案:

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

q命令的优点sed是读到第8000行就退出(不同于其他perlawk方法(普通创意后改了,哈哈))。

纯粹的 Bash 可能性(bash?4):

mapfile -s 7999 -n 1 ary < file
printf '%s' "${ary[0]}"
Run Code Online (Sandbox Code Playgroud)

这将删除file数组中的内容ary(每个字段一行),但跳过前 7999 行 ( -s 7999) 并且只读取一行 ( -n 1)。


ter*_*don 9

今天是星期六,我无事可做,所以我测试了其中的一些速度。事实证明sedgawkperl方法基本上是等价的。head&tail 是最慢的,但令人惊讶的是,最快的一个数量级是纯 bash :

这是我的测试:

$ for i in {1..5000000}; do echo "This is line $i" >>file; done
Run Code Online (Sandbox Code Playgroud)

上面创建了一个 5000 万行的文件,占用了 100M。

$ for cmd in "sed -n '8000{p;q}' file" \
            "perl -ne 'print && exit if $. == 8000' file" \
            "awk 'FNR==8000 {print;exit}' file" 
            "head -n 8000 file | tail -n 1" \
            "mapfile -s 7999 -n 1 ary < file; printf '%s' \"${ary[0]}\"" \
            "tail -n 8001 file | head -n 1"; do 
    echo "$cmd"; for i in {1..100}; do
     (time eval "$cmd") 2>&1 | grep -oP 'real.*?m\K[\d\.]+'; done | 
        awk '{k+=$1}END{print k/100}'; 
    done
sed -n '8000{p;q}' file
0.04502
perl -ne 'print && exit if $. == 8000' file
0.04698
awk 'FNR==8000 {print;exit}' file
0.04647
head -n 8000 file | tail -n 1
0.06842
mapfile -s 7999 -n 1 ary < file; printf '%s' "This is line 8000
"
0.00137
tail -n 8001 file | head -n 1
0.0033
Run Code Online (Sandbox Code Playgroud)


cuo*_*glm 6

您可以通过多种方式做到这一点。

使用perl

perl -nle 'print && exit if $. == 8000' file
Run Code Online (Sandbox Code Playgroud)

使用awk

awk 'FNR==8000 {print;exit}' file
Run Code Online (Sandbox Code Playgroud)

或者您可以使用tailhead来防止在第 8000 行之前读取整个文件:

tail -n +8000 | head -n 1
Run Code Online (Sandbox Code Playgroud)