如何重命名日志或错误文件以防止覆盖?我有一个生成输出日志文件的 bash 脚本。当重新运行脚本时,我希望通过根据最后创建的文件的名称更改每个日志文件的名称来保留旧日志文件。例如:
第一次运行:script.sh > log.file 生成 log.file1 第二次运行:script.sh > log.file 生成 log.file2 第三次运行:script.sh > log.file 生成 log.file3 基本上每次运行都需要检查最后一个日志文件并计数一个。
答案1
另一种(更好的?)方法是将日期和时间包含在日志文件的名称中。这样每次都会给您一个唯一的名称,它比仅使用数字更能提供信息,并且它不依赖于检查预先存在的文件。
示例:将数据输出到名为“$(date +"%Y_%m_%d_%I_%M_%p").log”的文件中
在bash中:
outputfilename="$(date +"%Y_%m_%d_%I_%M_%p").log" && generatelogstuff > "$outputfilename"
看:https://unix.stackexchange.com/questions/278939/how-do-you-put-date-and-time-in-a-file-name
答案2
下面是一个如何使用 bash 中的循环执行此操作的示例:
i=1
filename="log.file"
while [ -f $filename$i ]
do
i=$((i + 1))
done
filename=$filename$i
script.sh > $filename
我们将得到i=1
,并且每次都会递增,直到log.file$i
创建一个名为的文件。这样,每次创建新文件时,都会将 的最后一个值i
附加到$filename
,然后将其用作脚本的输出文件。
答案3
一个选项(不需要每次都明确计算新文件名)是写入暂时的日志文件,然后使用以下--backup=numbered
选项复制或移动它:
$ tmplog=$(mktemp)
$ ./script.sh > "$tmplog" && cp --backup=numbered "$tmplog" log
$ ./script.sh > "$tmplog" && cp --backup=numbered "$tmplog" log
$ ./script.sh > "$tmplog" && cp --backup=numbered "$tmplog" log
$ ./script.sh > "$tmplog" && cp --backup=numbered "$tmplog" log
$ rm "$tmplog"
从而产生自动编号的日志文件序列,
$ ls -1tr log*
log.~1~
log.~2~
log.~3~
log
答案4
我是这个 stackexchange 小组的新手,显然我不允许发表评论,因此我不得不这样回答:
在我发布这篇文章时看到的几个解决方案都存在可能导致问题的竞争条件。
例如增加计数器:从您检查 -f $filename$i 到您创建此类文件名(如果该文件名尚不存在)之间,脚本的多个实例可能正在运行。在这种情况下,由于您使用的是 >,因此可能会丢失一个实例。
例如,在文件名中放置时间戳:类似地,两个实例可能在完全相同的时间运行,无论 Sam 指示的时间粒度如何。
例如,写入相同的临时文件名,然后将其移动到版本化的文件名......类似的问题。
最标准的解决方案可能是将进程 ID 嵌入文件名中 - 例如,它可能看起来像 base.seq#.timestamp.pid。大多数 UNIX 都要求 PID 是唯一的。... 直到它被回收(不太可能)。... 或者如果您正在访问网络文件系统,则从没有相同进程 ID 空间的单独 OS 实例。添加主机名作为创可贴?... 但主机名不一定是唯一的,即使有完整的域也不一定是唯一的,有 NAT 或 MAC 号码的 IP 地址也不一定是唯一的。即使在单个系统上,有时人们也会使用操作系统不知道的自己的用户级协作多线程库……是的,其中一些将允许您进行系统调用。
最通用的解决方案是消除窗口/竞争条件:允许您测试 filename$i 是否已存在,如果不存在则返回新打开的文件描述符。原子地。但即使您的操作系统支持这一点,也并非所有文件系统都支持。(“重命名”方法流行的原因之一是,当最终添加 rename() 系统调用时,它在这方面有更好的保证。)
无论如何,我宁愿对此发表评论,因为现在我不记得是否有一个适用于 UNIX 系列(尤其是 Ubuntu)的 BKM。作为一个老顽固,我知道这是一个长期存在的错误来源,但我不知道它是否已完全解决,特别是对于最通用的网络和云文件系统。
但是,既然已经指出了这里可能存在问题,我可以退一步说,如果您了解环境,例如您没有在网络文件系统上运行,那么在 shell 脚本中,您经常可以采用触发我的多处理器危险信号的答案所建议的一些解决方案,尤其是 filename.timestamp.PID。尤其是如果您知道您不需要担心 DIY 多线程包,只需要 OS 标准多线程。
我希望有人能通过提供保证始终在所有 Ubuntu / 类 UNIX 系统代码序列上运行来纠正我......无论有没有网络文件系统或云文件系统或 FUSE 文件系统的限制......