在这个答案中(如何使用 sed 删除文件的第一行?)有两种方法可以删除文件中的第一条记录:
sed '1d' $file >> headerless.txt
Run Code Online (Sandbox Code Playgroud)
** - - - - - - - - 或者 - - - - - - - - **
tail -n +2 $file >> headerless.txt
Run Code Online (Sandbox Code Playgroud)
我个人认为该tail
选项在外观上更令人愉悦且更具可读性,但可能是因为我受到了sed-challenged。
哪种方法最快?
Byt*_*der 28
sed
vs.tail
删除文件第一行的性能sed
非常强大且用途广泛,但这就是它变慢的原因,尤其是对于包含多行的大文件。
tail
只做一件简单的事情,但它做得很好而且很快,即使对于有很多行的大文件也是如此。
对于中小型文件,sed
并且tail
执行速度相似(或慢,取决于您的期望)。然而,对于较大的输入文件(多个 MB),性能差异显着增加(数百 MB 范围内的文件的数量级),tail
明显优于sed
.
我们要分析的命令是:
sed '1d' testfile > /dev/null
tail -n +2 testfile > /dev/null
Run Code Online (Sandbox Code Playgroud)
请注意,我/dev/null
每次都将输出通过管道传输,以消除终端输出或文件写入作为性能瓶颈。
让我们设置一个 RAM 磁盘来消除作为潜在瓶颈的磁盘 I/O。我个人有一个tmpfs
安装在,/tmp
所以我只是把我的放在testfile
那里进行这个实验。
然后我曾经$numoflines
使用这个命令创建了一个随机测试文件,其中包含指定数量的具有随机行长度和随机数据的行(请注意,它绝对不是最佳的,大约 >2M 行它变得非常慢,但谁在乎,它不是我们正在分析的东西):
cat /dev/urandom | base64 -w0 | tr 'n' '\n'| head -n "$numoflines" > testfile
Run Code Online (Sandbox Code Playgroud)
哦,顺便说一句。我的测试笔记本电脑在 Intel i5-6200U CPU 上运行 64 位 Ubuntu 16.04。只是为了比较。
testfile
:运行上面的命令numoflines=10000000
生成一个包含 10M 行的随机文件,占用 600 MB 多一点 - 它相当大,但让我们从它开始,因为我们可以:
$ wc -l testfile
10000000 testfile
$ du -h testfile
611M testfile
$ head -n 3 testfile
qOWrzWppWJxx0e59o2uuvkrfjQbzos8Z0RWcCQPMGFPueRKqoy1mpgjHcSgtsRXLrZ8S4CU8w6O6pxkKa3JbJD7QNyiHb4o95TSKkdTBYs8uUOCRKPu6BbvG
NklpTCRzUgZK
O/lcQwmJXl1CGr5vQAbpM7TRNkx6XusYrO
Run Code Online (Sandbox Code Playgroud)
testfile
:现在让我们首先使用两个命令进行一次定时运行,以估计我们正在工作的幅度。
$ time sed '1d' testfile > /dev/null
real 0m2.104s
user 0m1.944s
sys 0m0.156s
$ time tail -n +2 testfile > /dev/null
real 0m0.181s
user 0m0.044s
sys 0m0.132s
Run Code Online (Sandbox Code Playgroud)
对于大文件,我们已经看到一个非常清晰的结果,tail
比sed
. 但只是为了好玩,并确保没有随机的副作用产生很大的不同,让我们做 100 次:
$ time for i in {1..100}; do sed '1d' testfile > /dev/null; done
real 3m36.756s
user 3m19.756s
sys 0m15.792s
$ time for i in {1..100}; do tail -n +2 testfile > /dev/null; done
real 0m14.573s
user 0m1.876s
sys 0m12.420s
Run Code Online (Sandbox Code Playgroud)
结论保持不变,sed
删除大文件的第一行效率低下,tail
应该在那里使用。
是的,我知道 Bash 的循环结构很慢,但是我们在这里只进行了相对较少的迭代,并且与sed
/tail
运行时相比,普通循环所花费的时间并不重要。
testfile
:现在为了完整起见,让我们看一下更常见的情况,即您有一个 kB 范围内的小输入文件。让我们用 来创建一个随机输入文件numoflines=100
,如下所示:
$ wc -l testfile
100 testfile
$ du -h testfile
8,0K testfile
$ head -n 3 testfile
tYMWxhi7GqV0DjWd
pemd0y3NgfBK4G4ho/
aItY/8crld2tZvsU5ly
Run Code Online (Sandbox Code Playgroud)
testfile
:根据经验,我们可以预期这些小文件的时间在几毫秒的范围内,让我们立即进行 1000 次迭代:
$ time for i in {1..1000}; do sed '1d' testfile > /dev/null; done
real 0m7.811s
user 0m0.412s
sys 0m7.020s
$ time for i in {1..1000}; do tail -n +2 testfile > /dev/null; done
real 0m7.485s
user 0m0.292s
sys 0m6.020s
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,时间非常相似,没有太多需要解释或想知道的。对于小文件,这两种工具同样适用。
这是另一种选择,仅使用 bash 内置函数和cat
:
{ read ; cat > headerless.txt; } < $file
Run Code Online (Sandbox Code Playgroud)
$file
被重定向到{ }
命令分组中。在read
简单的读取和丢弃的第一道防线。流的其余部分然后通过管道将cat
其写入目标文件。
在我的 Ubuntu 16.04 上,这个和tail
解决方案的性能非常相似。我创建了一个较大的测试文件seq
:
$ seq 100000000 > 100M.txt
$ ls -l 100M.txt
-rw-rw-r-- 1 ubuntu ubuntu 888888898 Dec 20 17:04 100M.txt
$
Run Code Online (Sandbox Code Playgroud)
tail
解决方案:$ time tail -n +2 100M.txt > headerless.txt
real 0m1.469s
user 0m0.052s
sys 0m0.784s
$
Run Code Online (Sandbox Code Playgroud)
cat
/支撑解决方案:$ time { read ; cat > headerless.txt; } < 100M.txt
real 0m1.877s
user 0m0.000s
sys 0m0.736s
$
Run Code Online (Sandbox Code Playgroud)
不过,我现在只有一个 Ubuntu 虚拟机,虽然它们都在同一个范围内,但两者的时间都存在显着差异。