如何使用bash / sed脚本删除文本文件的第一行?

我需要使用bash脚本从一个巨大的文本文件中重复删除第一行。

现在我正在使用sed -i -e "1d" $FILE – 但大约需要一分钟的时间才能删除。

有没有更有效的方法来完成这个?

尝试GNU tail :

 tail -n +2 "$FILE" 

-nx :只需打印最后的x行。 tail -n 5会给你input的最后5行。 +符号types颠倒了参​​数,并使tail打印除第一个x-1行以外的任何东西。 tail -n +1会打印整个文件, tail -n +2除了第一行之外都是

GNU tailsed快得多。 tail也可以在BSD上使用,并且-n +2标志在两个工具上都是一致的。 检查FreeBSD或OS X手册页以获取更多信息。

虽然BSD版本可能比sed慢得多。 我想知道他们是如何pipe理的。 tail应该只是逐行阅读一个文件,而sed执行相当复杂的操作,包括解释脚本,应用正则expression式等等。

注意:您可能会尝试使用

 # THIS WILL GIVE YOU AN EMPTY FILE! tail -n +2 "$FILE" > "$FILE" 

但这会给你一个空的文件 。 原因是redirect( > )在shell调用tail之前发生:

  1. Shell截断文件$FILE
  2. Shell为tail创build一个新的过程
  3. Shell将tail进程的stdoutredirect到$FILE
  4. tail从现在空的$FILE读取

如果你想删除文件中的第一行,你应该使用:

 tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE" 

&&将确保文件在出现问题时不会被覆盖。

对于非GNU的SunOS用户,以下代码将有所帮助:

 sed '1d' test.dat > tmp.dat 

您可以使用-i更新文件,而不使用“>”运算符。 以下命令将从文件中删除第一行并将其保存到文件中。

 sed -i '1d' filename 

不,那就像你将要得到的效率一样。 你可以编写一个C程序,它可以更快地完成这个工作(启动时间和处理参数less),但是它可能会趋于与sed相同的速度,因为文件变得很大(而且我认为如果它花了一分钟)。

但是,您的问题与其他许多人一样,也存在着同样的问题,因为它预先设定了解决scheme。 如果你要详细地告诉我们你想做什么,而不是如何 ,我们可能会build议一个更好的select。

例如,如果这是某个其他程序B处理的文件A,则一种解决scheme是不剥离第一行,但修改程序B以不同的方式处理它。

假设所有的程序附加到这个文件A中,并且程序B当前在删除它之前读取和处理第一行。

您可以重新devise程序B,以便它不会尝试删除第一行,而是在文件A中保留一个持久的(可能是基于文件的)偏移量,以便在下一次运行时可以寻找该偏移量,在那里的行,并更新偏移量。

然后,在安静的时间(午夜?),它可以对文件A进行特殊处理,删除当前处理的所有行,并将偏移量设置回0。

程序打开和查找文件肯定会更快,而不是打开和重写。 当然,这个讨论假设你对程序B有控制权。 我不知道是否是这种情况,但如果您提供进一步的信息,可能会有其他可能的解决scheme。

可以编辑这些文件:只需使用perl的-i标志,如下所示:

 perl -ni -e 'print unless $. == 1' filename.txt 

正如你所问,这使得第一行消失。 Perl将需要读取和复制整个文件,但它会将输出保存在原始文件的名称下。

Pax说,你可能不会比这更快。 原因是几乎没有文件系统支持从文件开头截断,所以这将是一个O( n )操作,其中n是文件的大小。 你可以做得更快,尽pipe用相同数量的字节(可能有空格或注释)覆盖第一行,这可能对你有用,具体取决于你想要做什么(顺便说一句,这是什么意思?)。

如何使用csplit?

 man csplit csplit -k file 1 '{1}' 

应该显示除第一行之外的行:

 cat textfile.txt | tail -n +2 

Sponge避免了杂耍临时文件的需要:

 tail -n +2 "$FILE" | sponge "$FILE" 

可以使用vim来做到这一点:

 vim -u NONE +'1d' +wq! /tmp/test.txt 

这应该是快速的,因为vim启动时不会读取整个文件。

既然听起来好像我无法加快删除速度,我认为一个好的方法可能是像这样批量处理文件:

 While file1 not empty file2 = head -n1000 file1 process file2 sed -i -e "1000d" file1 end 

这样做的缺点是,如果程序在中间死亡(或者如果在那里有一些坏的sql – 导致“进程”部分死亡或locking),将会有线被跳过或处理两次。

(file1包含sql代码行)

如果你想要做的是失败后恢复,你可以build立一个文件,到目前为止你已经做了。

 if [[ -f $tmpf ]] ; then rm -f $tmpf fi cat $srcf | while read line ; do # process line echo "$line" >> $tmpf done 

在N-1行上使用尾部并将其引导到文件中,然后删除旧文件,并将新文件重命名为旧名称,是否可以完成这项工作?

如果我正在以编程方式进行,我会通读文件,在读完每一行之后记住文件偏移量,这样我就可以回到那个位置去阅读文件,只用less一行。