我需要使用bash脚本从一个巨大的文本文件中反复删除第一行。
目前我正在使用sed -i -e "1d" $FILE
,但它需要约一分钟才能完成删除。
是否有更有效的方法来完成这个任务?
我需要使用bash脚本从一个巨大的文本文件中反复删除第一行。
目前我正在使用sed -i -e "1d" $FILE
,但它需要约一分钟才能完成删除。
是否有更有效的方法来完成这个任务?
尝试使用tail命令:
tail -n +2 "$FILE"
-n x
: 打印最后的 x
行。例如,tail -n 5
将给出输入的最后 5 行。加号 +
反转参数并使 tail
打印除前 x-1
行之外的所有行。例如,tail -n +1
将打印整个文件,tail -n +2
打印除第一行外的所有内容等。
GNU tail
比 sed
快得多。在 BSD 上也可以使用 tail
,而 -n +2
标志在两个工具中是一致的。请参阅FreeBSD或OS X手册以获取更多信息。
然而,在某些情况下,BSD 版本可能比 sed
慢得多。这让我很奇怪;tail
应该只需要逐行读取文件,而 sed
则需要执行涉及脚本解释、应用正则表达式等相当复杂的操作。
注意:您可能会想使用
# THIS WILL GIVE YOU AN EMPTY FILE!
tail -n +2 "$FILE" > "$FILE"
但这会给你一个空文件。原因是重定向(>
)发生在shell调用tail
之前:
$FILE
tail
创建一个新进程tail
进程的标准输出重定向到$FILE
tail
从现在的空白$FILE
中读取如果你想要删除文件内的第一行,你应该使用:
tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"
&&
会确保在出现问题时文件不被覆盖。
-r
选项时,典型的缓冲区默认为 32k。系统中可能有某个缓冲设置吗?或者 -n
是一个 32 位带符号数? - Yzmir Ramirezsed
有一个当前行的内部缓冲区,而tail
只需记住最后N个换行符的偏移量即可(请注意,我实际上没有查看源代码)。 - Aaron Digullased -i '1,2d' filename
命令。 - The Godfathersed -i'' '1d' filename
。根据https://dev59.com/FWQn5IYBdhLWcg3wiXud。 - Ahmad Abdelghany对于那些使用非GNU的SunOS操作系统的用户,以下代码将会有所帮助:
sed '1d' test.dat > tmp.dat
你可以轻松使用以下方法来实现:
cat filename | sed 1d > filename_without_first_line
在命令行上可以使用sed命令,或者使用sed的就地模式(-i
标志)永久删除文件的第一行:
sed -i 1d <filename>
-i
选项技术上需要一个参数来指定文件备份时要使用的后缀名(例如,sed -I .bak 1d filename
会创建一个名为 filename.bak
的副本,其中包含原始文件的第一行)。虽然 GNU sed 允许您指定不带参数的 -i
来跳过备份,但是在 macOS 上找到的 BSD sed 需要一个空字符串作为单独的 shell 单词参数(例如,sed -i '' ...
)。 - Mark Reedsponge
工具 避免了需要处理临时文件的麻烦:
tail -n +2 "$FILE" | sponge "$FILE"
sponge
确实比已接受的解决方案(tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"
)更加干净和健壮。 - Jealiesponge
会在内存中缓存整个文件吗?如果文件大小达到几百GB,那就无法工作了。 - OrangeDogsponge
就会吸收它,因为它使用 /tmp 文件作为中间步骤,然后用它来替换原始文件。 - agcawk FNR-1 *.csv
可能更快。 - jinaweeed
而不是其streaming后继者sed
:ed "$FILE" <<<$'1d\nwq\n'
ed
命令是最初的UNIX文本编辑器,甚至在全屏终端和图形工作站出现之前就已经存在了。 ex
编辑器是基于 ed
的扩展版本,最著名的用法是在 vi
冒号提示符下输入命令。因此,许多相同的命令也可以在 ex
中使用。虽然 ed
通常用于交互式使用,但也可以通过向它发送一系列命令来批处理使用,这就是这个解决方案的做法。
序列 <<<$'1d\nwq\n'
利用现代Shell对Here-strings(<<<
)和ANSI引用($'
...'
)的支持,将两行命令作为输入传递给 ed
命令:第一行是 1d
,表示删除第一行;第二行是 wq
,表示先写回到磁盘上,再退出编辑会话。
你可以在原地编辑文件:只需使用Perl的-i
标识,像这样:
perl -ni -e 'print unless $. == 1' filename.txt
这会使得第一行消失,就像您想要的那样。Perl需要读取并复制整个文件,但它会安排输出保存在原始文件名下。
正如Pax所说,你可能无法做得比这更快。原因是几乎没有文件系统支持从文件开头截断,因此这将是一个O(n
)操作,其中n
是文件的大小。然而,您可以用相同数量的字节(也许是空格或注释)覆盖第一行,这样可以更快地完成,具体取决于您要做什么(顺便问一下,您到底想做什么?)。
应该显示除第一行以外的所有行:
cat textfile.txt | tail -n +2