我需要使用bash脚本从巨大的文本文件中反复删除第一行。
目前,我正在使用sed -i -e "1d" $FILE
-但删除大约需要一分钟。
有没有更有效的方法来实现这一目标?
我需要使用bash脚本从巨大的文本文件中反复删除第一行。
目前,我正在使用sed -i -e "1d" $FILE
-但删除大约需要一分钟。
有没有更有效的方法来实现这一目标?
Answers:
试试tail:
tail -n +2 "$FILE"
-n x
:仅打印最后x
几行。tail -n 5
将为您提供输入的最后5行。该+
标志那种反转的争论,使tail
打印任何东西,但第一x-1
线。tail -n +1
将打印整个文件,tail -n +2
除了第一行以外的所有内容,等等。
GNU tail
比.NET 快得多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
外壳程序调用之前:
$FILE
tail
tail
流程的标准输出重定向到$FILE
tail
从现在的空读取 $FILE
如果要删除文件中的第一行,则应使用:
tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"
在&&
将确保该文件不被覆盖时,有一个问题。
tail
就适用于任何文件大小。
-n N means output the last N lines, instead of the last 10; or use +N to output lines starting with the Nth
您可以使用-i来更新文件,而无需使用'>'运算符。以下命令将从文件中删除第一行并将其保存到文件中。
sed -i '1d' filename
unterminated transform source string
sed -i '1,2d' filename
tail -n +2
。不知道为什么它不是最佳答案。
不,这与您将要获得的效率差不多。您可以编写一个C程序,该程序可以更快地完成工作(更少的启动时间和处理参数),但是随着文件变大,它可能趋向于与sed相同的速度(如果花一分钟,我认为它们会变大) )。
但是您的问题与其他许多问题一样面临着同样的问题,因为它预先提出了解决方案。如果你要详细告诉我们什么你想要做而不是如何,我们也许能够提出更好的选择。
例如,如果这是其他程序B处理的文件A,则一种解决方案是不剥离第一行,而修改程序B以不同方式处理它。
假设您的所有程序都附加到此文件A,并且程序B当前在删除第一行之前对其进行读取和处理。
您可以重新设计程序B,以便它不会尝试删除第一行,而是在文件A中保留一个持久的(可能是基于文件的)偏移量,以便在下次运行时可以查找该偏移量,然后进行处理。那里的线,并更新偏移量。
然后,在安静的时间(午夜?),它可以对文件A进行特殊处理,以删除当前处理的所有行并将偏移量设置回0。
程序打开和查找文件肯定比打开并重写更快。当然,该讨论假定您已控制程序B。我不知道是这种情况,但是如果您提供更多信息,可能还有其他可能的解决方案。
awk FNR-1 *.csv
可能更快。
您可以轻松地做到这一点:
cat filename | sed 1d > filename_without_first_line
在命令行上;或要永久删除文件的第一行,请使用sed的就地模式和以下-i
标志:
sed -i 1d <filename>
正如Pax所说,您可能不会比这更快。原因是几乎没有文件系统支持从文件开头截断,因此这将是O(n
)操作,其中n
文件的大小是。你可以做多,虽然速度是覆盖具有相同的字节数(也许用空格或注释),这可能会为您取决于正是你正在尝试做的工作第一线(那是什么来着?)。
的 sponge
UTIL避免了杂耍一个临时文件的需要:
tail -n +2 "$FILE" | sponge "$FILE"
sponge
确实比接受的解决方案更清洁,更可靠(tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"
)
sponge
将整个文件缓冲在内存中?如果只有数百GB,那将是行不通的。
sponge
就将其吸收,因为它使用/ tmp文件作为中间步骤,然后用于替换原始文件。
如果要修改到位的文件,你总是可以使用原始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编辑会话。
可以使用vim来做到这一点:
vim -u NONE +'1d' +'wq!' /tmp/test.txt
这应该更快,因为vim在处理时不会读取整个文件。
+wq!
如果您的外壳是bash ,则可能需要引用。可能不是因为!
单词不是开头,而是养成引用事物的习惯可能对所有人都有利。(并且,如果您不通过不必要的引用来提高效率,则不需要在两者之间都使用引号1d
。)
是否会在N-1行上使用tail并将其定向到文件中,然后删除旧文件,然后将新文件重命名为旧名称呢?
如果我以编程方式执行此操作,则在读取每一行后,我将通读文件,并记住文件偏移量,因此我可以返回该位置以读取其中少一行的文件。