我正在监视一个日志文件,如果PATTERN
在 THRESHOLD
秒内没有出现在其中,脚本应该打印"错误",否则,它应该打印"清除"。脚本工作正常,但前提是日志正在滚动。
我试过阅读"超时",但没有用。
log_file=/tmp/app.log
threshold=120
tail -Fn0 ${log_file} |
while read line ; do
echo "${line}" | awk '/PATTERN/ { system("touch pattern.tmp") }'
用于计算多久以前模式.tmp触摸和相同分配给DIFF
if [ ${diff} -gt ${threshold} ]; then
echo "Error"
else
echo "Clear"
done
仅当应用程序中打印了"任何"行时,它才会按预期工作.log。
如果应用程序因任何原因挂起并且日志停止滚动,则脚本不会有任何输出。
有没有办法检测tail
的"无输出"并在那时执行一些命令?
看起来您遇到的问题是,当while
阻塞输入时,循环内的时序计算永远不会有机会运行read
。在这种情况下,您可以将tail
输出通过管道传输到while true
循环中,您可以在其中执行if read -t $timeout
:
log_file=/tmp/app.log
threshold=120
timeout=10
tail -Fn0 "$log_file" | while true; do
if read -t $timeout line; then
echo "${line}" | awk '/PATTERN/ { system("touch pattern.tmp") }'
fi
# code to calculate how long ago pattern.tmp touched and same is assigned to diff
if [ ${diff} -gt ${threshold} ]; then
echo "Error"
else
echo "Clear"
fi
done
正如 Ed Morton 指出的那样,在 bash 脚本中,所有大写变量名称都不是一个好主意,所以我使用了小写变量名称。
像这样简单的事情怎么样:
sleep "$threshold"
grep -q 'PATTERN' "$log_file" && { echo "Clear"; exit; }
echo "Error"
如果这不是您所需要的全部,请编辑您的问题以阐明您的要求。顺便说一句,不要对非导出的 shell 变量名称使用全部大写 - 谷歌一下。
为了进一步构建您的想法,在后台运行 awk 部分并连续循环进行检查可能是有益的。
#!/usr/bin/env bash
log_file="log.txt"
# threshold in seconds
threshold=10
# run the following process in the background
stdbuf -oL tail -f0n "$log_file"
| awk '/PATTERN/{system("touch "pattern.tmp") }' &
while true; do
match=$(find . -type f -iname "pattern.tmp" -newermt "-${threshold} seconds")
if [[ -z "${match}" ]]; then
echo "Error"
else
echo "Clear"
fi
done
这就像一个看门狗计时器。我已经通过强制后台进程更新我的日志来实现这样的事情,所以我不必担心read -t
.下面是一个工作示例:
#!/usr/bin/env bash
threshold=10
grain=2
errorstate=0
while sleep "$grain"; do
date '+[%F %T] watchdog timer' >> log
done &
trap "kill -HUP $!" 0 HUP INT QUIT TRAP ABRT TERM
printf -v lastseen '%(%s)T'
tail -F log | while read line; do
printf -v now '%(%s)T'
if (( now - lastseen > threshold )); then
echo "ERROR"
errorstate=1
else
if (( errorstate )); then
echo "Recovered, yay"
errorstate=0
fi
fi
if [[ $line =~ .*PATTERN.* ]]; then
lastseen=$now
fi
done
在一个窗口中运行它,等待$threshold
秒以触发它,然后在另一个窗口中echo PATTERN >> log
以查看恢复。
虽然这可以像您喜欢的那样精细(我在示例中将其设置为 2 秒(,但它确实会污染您的日志文件。
哦,请注意,printf '%(%s)T'
格式需要 bash 版本 4 或更高版本。