首页 > 解决方案 > 从进程主动写入的bash内联中的文件开头删除前N个字节/行

问题描述

在连续记录数据时,我需要从日志文件中删除/截断前 N 个字节。例如 nohup.out

虽然我可以bash像这样使用截断命令。

truncate -c -s -10K my_file.

这将截断文件末尾的最新数据。所以在这种情况下没有用。

我需要从文件开头截断文件(具有旧数据)并保留新文件。

我在网上查了一下,大多数示例都使用重定向或写入临时文件ddhead。我需要在同一个文件上内联执行此操作。

最接近的匹配是sed,但到目前为止,我发现了从每一行中截断 N 个字符的示例。例如,下面将从 my_file 中的每一行删除 10 个字节。

sed -i 's/^\(.\)\{10\}//g' my_file

我正在寻找可以删除前 N 个字节的选项,从第 1 行开始,到第 K 行结束,其中第 N 个字节删除结束,从而在底部保留最新数据。

我可能可以编造一些逻辑来实现这一点,但想知道是否有“现成的”选项可用。

任何指针?谢谢。

标签: bashsed

解决方案


以下将打印行,直到包含第 N 个字节的行:

awk -v n="$n" 'c>=n{exit} {c+=length()+1} 1'

其中 shell 变量$n包含对您很重要的字节数。在+1那里,以便包含换行符。如果您没有单字符换行符,请调整以适应,或者length(ORS)改用。

请注意,这不会处理您请求中不可能的部分,即在另一个进程打开文件进行写入时更改文件。

为了实现与此相反的操作——也就是说,打印从第 N 个字节开始的每一行,我们需要一些稍微不同的东西:

awk -v n="$n" 'c>=n{p=1} {c+=length()+1} p'

这将设置一个信号量,p一旦看到足够的字符,如果信号量评估为真,则打印。

性能低得多的等效 bash-only 版本可能如下所示:

c=0; p=0
while read; do
  ((c>=n)) && p=1
  ((c+=${#REPLY}+1))
  ((p)) && echo "$REPLY"
done

您可以将其用作管道,或使用输入重定向来读取文件。它还假设$n包含一个整数。


推荐阅读