如何保留日志文件中的最后 50 行

如何保留日志文件中的最后 50 行

我尝试在文件中保留最后 50 行,每分钟保存一次温度。我使用了这个命令:

tail -n 50 /home/pi/Documents/test > /home/pi/Documents/test

但结果是空的测试文件。我想,它会列出测试文件的最后 50 行并将其插入到测试文件中。当我使用这个命令时:

tail -n 50 /home/pi/Documents/test > /home/pi/Documents/test2

它工作正常。 test2 文件中有 50 行。

有人能解释一下问题出在哪里吗?

答案1

问题是您的 shell 在运行命令之前设置命令管道。这不是“输入和输出”的问题,而是文件的内容在 tail 运行之前就已经消失了。它是这样的:

  1. shell 打开>输出文件进行写入,并截断它
  2. shell 设置文件描述符 1(用于标准输出)用于该输出
  3. 外壳执行tail.
  4. tail运行,打开/home/pi/Documents/test,发现什么也没有

解决方案有很多种,但关键是要了解问题所在、到底出了什么问题以及原因。

这将产生您正在寻找的东西,

echo "$(tail -n 50 /home/pi/Documents/test)" > /home/pi/Documents/test

解释 :

  • $()称为命令替换,执行tail -n 50 /home/pi/Documents/test
  • 引号在输出中保留换行符。
  • > /home/pi/Documents/test将 的输出重定向echo "$(tail -n 50 /home/pi/Documents/test)"到同一文件。

答案2

文件重定向首先清除文件的另一个解决方案是sponge使用moreutils像这样打包:

tail -n 50 /home/pi/Documents/test | sponge /home/pi/Documents/test

答案3

这是因为 bash 首先处理重定向>,删除文件的内容。然后它执行命令。如果您使用>>,最后 50 行将被附加到文件中当前内容的末尾。在本例中,相同的 50 行会重复两次。

当重定向到不同的文件时,该命令按预期工作。以下是将文件的最后 50 行写入同名文件的一种方法:

tail -50 /home/pi/Documents/test > /home/pi/Documents/test2 && mv /home/pi/Documents/test2 /home/pi/Documents/test

这首先将最后 50 行写入临时文件,然后将其移动mv以替换原始文件。

正如评论中所指出的,如果文件仍然打开,这将不起作用。移动文件还会创建新的索引节点,并可能更改所有权和权限。使用临时文件执行此操作的更好方法是:

tail -50 /home/pi/Documents/test > /home/pi/Documents/test2 ; cat /home/pi/Documents/test2 > /home/pi/Documents/test

临时文件也可以被删除,尽管每次发生这种情况时其内容都会被覆盖。

答案4

既然您已经了解了 shell 重定向的主要问题,那么这里有另一种方法可以将文件修剪到最后 50 行:

file=/path/to/the/file
n=$(( $(wc -l < "$file") - 50 ))
[[ $n -gt 0 ]] && sed -i 1,${n}d "$file"

这项艰苦的工作是由 (GNU) sed 的-i“就地编辑”功能完成的,该功能通过在临时文件中创建输出来在幕后工作。其余行设置 sed 操作的数学,即:

  1. 计算文件中的行数 ( wc),然后减去 50;将其分配给n.
  2. 如果n 为正,则运行 sed 命令删除第 1 行到第 n 行。

相关内容