Shell:删除一个巨大文本日志文件的最后一行。

18

我在stackoverflow上提问,询问如何在PHP中弹出文本文件的最后一行,现在,是否可以用shell脚本重写这个逻辑呢?

我尝试了以下方法来获取最后一行:

tail -n 1 my_log_file.log

但我不确定如何删除最后一行并保存文件。

附:我使用的是Ubuntu服务器。

4个回答

34

要获取文件内容,不包含最后一行,您可以使用

head -n-1 logfile.log

我不确定这在所有地方都被支持。

或者

sed '$d' logfile.log

完美!!!棒极了。 - Satish
1
sed 命令完美地运行了!$d 是在最后一行之前退出的命令,因此它可以跳过最后一行!请参见 https://www.gnu.org/software/sed/manual/sed.html。 - nothize

26
你想要的是截取文件在最后一行之前而不必读取整个文件。
truncate -s -"$(tail -n1 file | wc -c)" file

假设该文件当前不在被写入的状态下。

truncate是GNU coreutils的一部分(因此通常可以在最新的Linux发行版中找到),并不是标准的Unix或POSIX命令。许多"dd"实现也可以用来截断文件。


使用 tail + truncate 将是更有效的解决方案。当然,为了允许 OP 检索最后一行的内容,应该单独调用 tail -n 并将其存储在一个变量中。然后可以使用 ${#VAR} + 1 作为截断大小。 - Shawn Chin
添加了一个维基答案,并提出了更改建议。 - Shawn Chin
3
尾部/字数统计组合前似乎有一个额外的“-”。另外,你可以在这里使用-r选项(使用给定文件的大小):如果你不介意bashism,可以用truncate -r <(tail -n1 file) file - chepner
1
进程替换是一种kshism(也被zsh和bash支持)。它不起作用,因为<(tail -n1 file)是一个管道,而我们想要削减那么多文件,而不是将文件截断为与其最后一行相同的大小。 - Stephane Chazelas
1
这应该是答案。快速、简单、有效。刚刚在一个5.2GB的文件上瞬间完成了。 - mcsilvio

16

(解决方案基于sch的答案,因此应该归功于他/她)

这种方法可以高效地检索文件的最后一行,并截断文件以删除该行。由于文件不是按顺序读取的,因此可以更好地处理大型输入。

# retrieve last line from file
LAST=$(tail -n 1 my_log_file.log)

# truncate file
let TRUNCATE_SIZE="${#LAST} + 1"
truncate -s -"$TRUNCATE_SIZE" my_log_file.log

# ... $LAST contains 'popped' last line

请注意,如果在调用tailtruncate之间修改文件,则其效果可能与预期不符。


1
请注意,与我提供的基于“wc”的解决方案相反,该解决方案仅适用于GNU系统,上述解决方案仅在最后一行包含NUL字符时才能正常工作。此外,如果最后一行没有以NL结尾,则它也无法正确工作。 - Stephane Chazelas
此外,truncate 函数期望的是 字节 大小,而 ${#LAST} 计算的是 $LAST 中字符的数量。为了使它们等效,您需要将区域设置为 C。否则,如果最后一行包含多字节字符,则无法正常工作。 - Stephane Chazelas

4

一种方法是:

sed '$d' < f1 > f2 ; mv f2 f1

我不明白这个。f2f1是什么? - Raptor
我来晚了,但这是我最喜欢的解决方案。你可以使用sed的“-i”标志直接进行更改:“sed -i -e '$d' my_log_file.log”。 - Capt. Crunch
1
在编写跨平台脚本时,使用“-i”时要小心,因为在macOS和Linux上的用法不同。 - bfontaine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接