监视文件直到找到字符串

监视文件直到找到字符串

我用tail -f它来监视正在写入的日志文件。当某个字符串写入日志文件时,我想退出监视并继续执行脚本的其余部分。

目前我正在使用:

tail -f logfile.log | grep -m 1 "Server Started"

当找到字符串时,grep按预期退出,但我需要找到一种方法来退出,tail以便脚本可以继续。

答案1

这是一个简单的单行代码。它不需要特定于 bash 或非 POSIX 的技巧,甚至不需要命名管道。您真正需要的只是将 的终止与 分离tailgrep这样,一旦结束,即使尚未结束,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"

相关内容