使用bash命令打印文件某个部分的最快方法

时间:2016-08-27 03:11:33

标签: bash shell sed

目前我正在使用sed来打印文件的所需部分。例如,我使用了以下命令

sed -n 89001,89009p file.xyz

但是,随着文件大小的增加,它的速度非常慢(我的文件目前为6.8 GB)。我试图遵循这个link并使用命令

sed -n '89001,89009{p;q}' file.xyz

但是,此命令仅打印第89001行。请帮助我。

6 个答案:

答案 0 :(得分:7)

语法略有不同:

sed -n '89001,89009p;89009q' file.xyz

<强>更新

由于还有 awk 的答案,我做了一个小比较,正如我想的那样 - sed 更快一点:

$ wc -l large-file 
100000000 large-file
$ du -h large-file 
954M    large-file
$ time sed -n '890000,890010p;890010q' large-file > /dev/null

real    0m0.141s
user    0m0.068s
sys 0m0.000s
$ time awk 'NR>=890000{print} NR==890010{exit}' large-file > /dev/null

real    0m0.433s
user    0m0.208s
sys 0m0.008s`

<强> UPDATE2:

由@EdMorton发布的 awk 有一种更快的方式,但仍然没有 sed 那么快:

$ time awk 'NR>=890000{print; if (NR==890010) exit}' large-file > /dev/null

real    0m0.252s
user    0m0.172s
sys     0m0.008s

<强>更新

这是我能找到的最快的方式():

$ time head -890010 large-file| tail -10 > /dev/null

real    0m0.085s
user    0m0.024s
sys     0m0.016s

答案 1 :(得分:4)

awk 'NR>=89001{print; if (NR==89009) exit}' file.xyz

答案 2 :(得分:2)

在awk中更易于阅读,性能应与sed

类似
awk 'NR>=89001{print} NR==89009{exit}' file.xyz

您也可以用分号替换{print}

答案 3 :(得分:2)

Dawid Grabowski's helpful answer是可行的方法(sed [1] ; Ed Morton's helpful answer是一种可行的awk替代方案; tail + head组合通常是最快的 [2]

至于为什么你的方法不起作用

89001,89009这样的双地址表达式选择一个包含范围的行,以起始和结束地址为界(在本例中为行号)。

然后为所选范围内的每一行执行相关的功能列表{p;q;}

因此,第#行89001是导致函数列表执行的第一行:在打印(p)之后,行执行函数q - 退出执行马上,没有处理任何其他行。

为了防止过早退出,Dawid的答案因此将打印(p)范围内的所有行与退出(q)处理分开,使用两个用;分隔的命令:

  • 89001,89009p打印范围
  • 中的所有行
  • 89009q在达到范围的终点时退出处理

[1]重复性稍差的重新制定应该同样表现良好($代表 last 行,由于第二个命令而永远不会达到这一点:
sed -n '89001,$ p; 89009 q' 功能

[2]从Dawid的回答中更好地重新阐述head + tail解决方案是 tail -n +89001 file | head -n 9,因为它限制了感兴趣的的字节数,但仍然以管道缓冲区大小通过管道发送(典型的管道缓冲区大小为64 KB)。
使用 GNU 实用程序(Linux),这是最快的解决方案,但在具有库存实用程序(BSD)的OSX上,sed解决方案最快。

答案 4 :(得分:0)

另一种方法是使用 head tail 的组合:

$ time head -890010 large-file| tail -10 > /dev/null

real    0m0.085s
user    0m0.024s
sys     0m0.016s

这比 sed awk 更快。

答案 5 :(得分:-2)

需要 sed 从文件的开头搜索才能找到第N行。为了加快速度,请使用和索引文件以固定行数间隔划分大文件。然后使用 dd 跳过大文件的早期部分,然后转到 sed

使用以下方法构建索引文件:

#!/bin/bash

INTERVAL=1000
LARGE_FILE="big-many-GB-file"
INDEX_FILE="index"

LASTSTONE=123
MILESTONE=0

echo $MILESTONE > $INDEX_FILE

while [ $MILESTONE != $LASTSTONE ] ;do

LASTSTONE=$MILESTONE
MILESTONE=$(dd if="$LARGE_FILE" bs=1 skip=$LASTSTONE 2>/dev/null |head -n$INTERVAL |wc -c)
MILESTONE=$(($LASTSTONE+$MILESTONE))
echo $MILESTONE >> $INDEX_FILE
done

exit

然后使用:./ this_script.sh 89001

搜索一行
#!/bin/bash

INTERVAL=1000
LARGE_FILE="big-many-GB-file"
INDEX_FILE="index"

LN=$(($1-1))

OFFSET=$(head -n$((1+($LN/$INTERVAL))) $INDEX_FILE |tail -n1)
LN=$(($LN-(($LN/$INTERVAL)*$INTERVAL)))
LN=$(($LN+1))
dd if="$LARGE_FILE" bs=1 skip=$OFFSET 2>/dev/null |sed -n "$LN"p