我需要使用bash脚本从一个巨大的文本文件中重复删除第一行.
现在我正在使用sed -i -e "1d" $FILE
- 但删除大约需要一分钟.
有没有更有效的方法来实现这一目标?
试试GNU尾巴:
tail -n +2 "$FILE"
-n x
:只需打印最后x
一行.tail -n 5
会给你输入的最后5行.该+
标志那种反转的争论,使tail
打印任何东西,但第一x-1
线.tail -n +1
将打印整个文件,tail -n +2
除第一行外的所有内容等.
GNU tail
要快得多sed
.tail
也可以在BSD上使用,并且-n +2
两个工具的标志是一致的.查看FreeBSD或OS X手册页了解更多信息.
不过,BSD版本可能要慢很多sed
.我想知道他们是如何做到的; tail
应该只是逐行读取文件,同时sed
执行相当复杂的操作,包括解释脚本,应用正则表达式等.
注意:您可能很想使用
# THIS WILL GIVE YOU AN EMPTY FILE! tail -n +2 "$FILE" > "$FILE"
但这会给你一个空文件.原因是重定向(>
)发生在tail
shell调用之前:
Shell截断文件 $FILE
Shell为其创建了一个新流程 tail
Shell将tail
进程的stdout重定向到$FILE
tail
从现在空的读取 $FILE
如果要删除文件中的第一行,则应使用:
tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"
这&&
将确保在出现问题时不会覆盖该文件.
您可以使用-i更新文件,而无需使用">"运算符.以下命令将从文件中删除第一行并将其保存到文件中.
sed -i '1d' filename
对于那些使用非GNU的SunOS的人,以下代码将有所帮助:
sed '1d' test.dat > tmp.dat
不,那就像你要获得的那样高效.您可以编写一个C程序,它可以更快地完成工作(减少启动时间和处理参数)但它可能会趋向于与文件变大的sed相同的速度(并且我认为如果它需要一分钟就会很大).
但是你的问题与许多其他问题一样,因为它预先设定了解决方案.如果你要详细告诉我们什么你想要做而不是如何,我们也许能够提出更好的选择.
例如,如果这是某个其他程序B处理的文件A,则一种解决方案是不剥离第一行,而是修改程序B以不同方式处理它.
假设所有程序都附加到此文件A,程序B当前在删除它之前读取并处理第一行.
您可以重新设计程序B,以便它不会尝试删除第一行但是在文件A中保持一个持久的(可能是基于文件的)偏移量,以便下次运行时可以寻找该偏移量,进程那条线,并更新偏移量.
然后,在安静的时间(午夜?),它可以对文件A进行特殊处理,以删除当前处理的所有行,并将偏移量设置回0.
程序打开和查找文件而不是打开和重写肯定会更快.当然,本讨论假定您可以控制程序B. 我不知道是否是这种情况,但如果您提供进一步的信息,可能还有其他可能的解决方案.
你可以编辑文件:只需使用perl的-i
标志,如下所示:
perl -ni -e 'print unless $. == 1' filename.txt
这会使第一行消失,正如你所问的那样.Perl需要读取和复制整个文件,但它会安排输出以原始文件的名称保存.
正如Pax所说,你可能不会比这更快.原因是几乎没有文件系统支持从文件开头截断,因此这将是一个O(n
)操作,其中n
是文件的大小.你可以做多,虽然速度是覆盖具有相同的字节数(也许用空格或注释),这可能会为您取决于正是你正在尝试做的工作第一线(那是什么来着?).
该sponge
UTIL避免了杂耍一个临时文件的需要:
tail -n +2 "$FILE" | sponge "$FILE"
如果要修改到位的文件,你总是可以使用原始ed
的,而不是它的小号 treaming继任者sed
:
ed "$FILE" <<<$'1d\nwq\n'
该ed
命令是原始的UNIX文本编辑器,甚至没有全屏终端,而图形工作站则少得多。在ex
编辑器中,最有名的你使用的是什么类型时,在结肠中的提示vi
,是一个前的趋向版本ed
,所以很多相同的命令工作。尽管ed
本意是要交互使用,但也可以通过向其发送一串命令来以批处理方式使用它,这就是该解决方案的作用。
序列<<<$'1d\nwq\n'
利用了bash的支持,这里串(<<<
)和POSIX引号($'
... '
),以饲料投入到ed
由两行命令:1d
,其中d eletes行1,然后wq
,这W¯¯仪式的文件重新出磁盘,然后q UITS编辑会话。
您可以轻松地做到这一点:
cat filename | sed 1d > filename_without_first_line
在命令行上;或要永久删除文件的第一行,请使用sed的就地模式和以下-i
标志:
sed -i 1d
可以使用vim来做到这一点:
vim -u NONE +'1d' +'wq!' /tmp/test.txt
这应该更快,因为vim在处理时不会读取整个文件。