我用tail -f
它来监视正在写入的日志文件。当某个字符串写入日志文件时,我想退出监视并继续执行脚本的其余部分。
目前我正在使用:
tail -f logfile.log | grep -m 1 "Server Started"
当找到字符串时,grep
按预期退出,但我需要找到一种方法来退出,tail
以便脚本可以继续。
答案1
这是一个简单的单行代码。它不需要特定于 bash 或非 POSIX 的技巧,甚至不需要命名管道。您真正需要的只是将 的终止与 分离tail
。grep
这样,一旦结束,即使尚未结束,grep
脚本也可以继续。因此,这个简单的方法将帮助您实现目标:tail
( tail -f -n0 logfile.log & ) | grep -q "Server Started"
grep
会一直阻塞直到找到字符串,然后退出。通过tail
从其自己的子 shell 运行,我们可以将其置于后台,以便它独立运行。同时,主 shell 可以在grep
退出时继续执行脚本。tail
会在其子 shell 中停留,直到下一行写入日志文件,然后退出(甚至可能在主脚本终止后)。重点是管道不再等待tail
终止,因此管道会在grep
退出时立即退出。
一些小的调整:
- 选项 -n0 使其
tail
从日志文件的当前最后一行开始读取,以防字符串在日志文件中较早存在。 - 您可能希望使用
tail
-F 而不是 -f。它不是 POSIX,但它允许tail
在等待时旋转日志也能正常工作。 - 选项 -q 而不是 -m1 会
grep
在第一次出现后退出,但不打印触发行。此外它是 POSIX,而 -m1 不是。
答案2
接受的答案对我来说不起作用,而且它令人困惑并且它会更改日志文件。
我正在使用这样的东西:
tail -f logfile.log | while read LOGLINE
do
[[ "${LOGLINE}" == *"Server Started"* ]] && pkill -P $$ tail
done
如果日志行与模式匹配,则终止tail
该脚本启动的进程。
注意:如果您还想在屏幕上查看输出,请| tee /dev/tty
在 while 循环中回显测试之前的那一行。
答案3
如果你使用 Bash(至少,但它似乎没有被 POSIX 定义,所以它可能在某些 shell 中缺失),你可以使用语法
grep -m 1 "Server Started" <(tail -f logfile.log)
它的工作原理与前面提到的 FIFO 解决方案非常相似,但编写起来更简单。
答案4
让我扩展@00prometheus 的回答(这是最好的一个)。
也许您应该使用超时而不是无限期地等待。
下面的 bash 函数将会阻塞,直到出现给定的搜索词或者达到给定的超时时间。
如果在超时内找到该字符串,则退出状态将为 0。
wait_str() {
local file="$1"; shift
local search_term="$1"; shift
local wait_time="${1:-5m}"; shift # 5 minutes as default timeout
(timeout $wait_time tail -F -n0 "$file" &) | grep -q "$search_term" && return 0
echo "Timeout of $wait_time reached. Unable to find '$search_term' in '$file'"
return 1
}
也许在启动服务器后日志文件还不存在。在这种情况下,您应该等待它出现后再搜索字符串:
wait_server() {
echo "Waiting for server..."
local server_log="$1"; shift
local wait_time="$1"; shift
wait_file "$server_log" 10 || { echo "Server log file missing: '$server_log'"; return 1; }
wait_str "$server_log" "Server Started" "$wait_time"
}
wait_file() {
local file="$1"; shift
local wait_seconds="${1:-10}"; shift # 10 seconds as default timeout
until test $((wait_seconds--)) -eq 0 -o -f "$file" ; do sleep 1; done
((++wait_seconds))
}
使用方法如下:
wait_server "/var/log/server.log" 5m && \
echo -e "\n-------------------------- Server READY --------------------------\n"