此问题的另一种形式发生在日志定期循环运行的长时间运行的应用程序中。即使您移动原始日志(例如mv log.txt log.1),并在实际记录发生之前立即将其替换为同名文件,但是如果该进程将文件保持打开状态,则最终要么写入log.1(因为这可能仍然是开放的inode)或什么都不做。
一种常见的处理方法(系统记录器本身就是这种方式)是在进程中实现信号处理程序,该程序将关闭并重新打开其日志。然后,每当您要移动或清除(通过删除)日志时,请将该信号立即发送到进程。
这是bash的一个简单演示-原谅我的外壳技巧(但是,如果您要针对最佳实践等进行编辑,请确保您首先了解该功能并在编辑之前测试修订):
#!/bin/bash
trap sighandler INT
function sighandler () {
touch log.txt
exec &> log.txt
}
echo $BASHPID
exec &> log.txt
count=0;
while [ $count -lt 60 ]; do
echo "$BASHPID Count is now $count"
sleep 2
((count++))
done
首先分叉到后台:
> ./test.sh &
12356
注意它向终端报告其PID,然后开始登录log.txt。您现在有2分钟的游戏时间。等待几秒钟,然后尝试:
> mv log.txt log.1 && kill -s 2 12356
在kill -2 12356这里,简单也可以为您工作。信号2是SIGINT(也是Ctrl-C的功能,因此您可以在前台尝试此操作并从另一个终端移动或删除日志文件),trap应该捕获该信号。去检查;
> cat log.1
12356 Count is now 0
12356 Count is now 1
12356 Count is now 2
12356 Count is now 3
12356 Count is now 4
12356 Count is now 5
12356 Count is now 6
12356 Count is now 7
12356 Count is now 8
12356 Count is now 9
12356 Count is now 10
12356 Count is now 11
12356 Count is now 12
12356 Count is now 13
12356 Count is now 14
现在,让我们看一下log.txt即使我们将其移动,它是否仍在写入:
> cat log.txt
12356 Count is now 15
12356 Count is now 16
12356 Count is now 17
12356 Count is now 18
12356 Count is now 19
12356 Count is now 20
12356 Count is now 21
请注意,它一直沿停止的地方继续前进。如果您不想保留记录,只需删除它即可清除日志
> rm -f log.txt && kill -s 2 12356
校验:
> cat log.txt
12356 Count is now 29
12356 Count is now 30
12356 Count is now 31
12356 Count is now 32
12356 Count is now 33
12356 Count is now 34
12356 Count is now 35
12356 Count is now 36
还在做。
不幸的是,您无法在shell脚本中为已执行的子进程执行此操作,因为如果它在前台,则bash自己的信号处理程序将trap被挂起,并且如果将其分叉到后台,则无法重新分配其输出。即,这是您必须在应用程序中实现的东西。
然而...
如果您不能修改应用程序(例如,因为您没有编写应用程序),那么我有一个CLI实用程序,您可以将其用作中介。您还可以在脚本中实现此操作的简单版本,该脚本充当通往日志的管道:
#!/bin/bash
trap sighandler INT
function sighandler () {
touch log.txt
exec 1> log.txt
}
echo "$0 $BASHPID"
exec 1> log.txt
count=0;
while read; do
echo $REPLY
done
让我们称之为pipetrap.sh。现在,我们需要一个单独的程序进行测试,以模仿您要记录的应用程序:
#!/bin/bash
count=0
while [ $count -lt 60 ]; do
echo "$BASHPID Count is now $count"
sleep 2
((count++))
done
那将是test.sh:
> (./test.sh | ./pipetrap.sh) &
./pipetrap.sh 15859
这是两个具有独立PID的独立过程。要清除test.sh的输出,该输出将通过pipetrap.sh以下渠道进行传送:
> rm -f log.txt && kill -s 2 15859
校验:
>cat log.txt
15858 Count is now 6
15858 Count is now 7
15858 Count is now 8
15858,test.sh仍在运行,并且正在记录其输出。在这种情况下,无需修改应用程序。