【问题标题】:How to get correct tail PID under multiple process in shell如何在shell中的多个进程下获得正确的尾PID
【发布时间】:2019-12-27 21:46:34
【问题描述】:

我正在实现monitor_log 函数,该函数将从运行日志中跟踪最新行并使用while循环检查所需的字符串,超时逻辑应该是当tail log运行超过300秒时,它必须关闭tail和while循环管道。参考How to timeout a tail pipeline properly on shell,上面提到即使monitor_log函数完成,它会在后台留下tail进程,所以我必须手动杀死它,以防数百次调用monitor_log会离开数百个tail 进程。

下面的函数monitor_log 杀死正确的tail PID 仅在单进程情况下,因为tail_pid=$(ps -ef | grep 'tail' | cut -d' ' -f5) 将返回正确的tail PID,它在唯一的进程上。当遇到多进程情况(进程fork),例如多次调用monitor_log函数并行tail log,会有多个tail进程在运行,tail_pid=$(ps -ef | grep 'tail' | cut -d' ' -f5)不能准确返回tail所属的PID到当前的分叉。

那么当monitor_log 函数完成时,有可能离开tail 进程吗?或者如果离开tail 进程,是否有适当的方法找到它的正确 PID(不是来自其他线程的tail PID)并在多进程情况下杀死它?

function monitor_log() {
  if [[ -f "running.log" ]]; then
    # Tail the running log last line and keep check required string
    while read -t 300 tail_line
    do
      if [[ "$tail_line" == "required string" ]]; then
        capture_flag=1
      fi
      if [[ $capture_flag -eq 1 ]]; then
        break;
      fi
    done < <(tail -n 1 -f "running.log")
    # Not get correct tail PID under multiple process
    tail_pid=$(ps -ef | grep 'tail' | cut -d' ' -f5)
    kill -13 $tail_pid
  fi
}

【问题讨论】:

  • 您的问题具有误导性 - bash 脚本中没有“多线程”。 Shell 脚本是关于进程分叉的。 Ofc 可以并行运行(多处理!= 多线程)
  • 好的,这是一个很好的建议,“多线程”是用于描述这里案例的错误术语,因为我对脚本的嵌入式机制有点新,让我更新为“进程分叉”跨度>
  • 也许将其称为“在后台并行运行多个调用” - 然后它会自动清除您想要实现的目标。
  • 是的,混蛋,还在检查它,感谢您的建议

标签: linux bash shell process fork


【解决方案1】:

你可以试试下面的代码:

function monitor_log() {
  if [[ -f "running.log" ]]; then
    # Tail the running log last line and keep check required string
    while read -t 300 tail_line
    do
      if [[ "$tail_line" == "required string" ]]; then
        capture_flag=1
      fi
      if [[ $capture_flag -eq 1 ]]; then
        break;
      fi
    done < <(tail -n 1 -f "running.log")

     tailpid=$!

     kill $tailpid
  fi
}

> 美元!给出在后台运行的最后一个作业的进程 ID (PID)

更新:这将杀死触发尾部的子shell,如评论中所建议的那样

另一种方法可能是在tail命令中添加超时,如下所示:

timeout 300s tail -n 1 -f "running.log"

【讨论】:

  • 谢谢 Alok,我已经尝试过了,但仍然不确定这是否会得到正确的 PID,因为我知道 tailwhile read loop 之后称为 sub shell,因为我观察到 tailpid通过$! 获得的 PID 与ps -ef | grep 'tail' 获得的 PID 不完全匹配,即使在单次呼叫下也是如此,但我需要更多测试来确认这一点。
  • 它返回子shell的PID(tail在那个子shell中运行)。
  • 是的,混蛋,同意“它返回子shell的PID(尾巴在那个子shell中运行)”,作为测试,就像Alok提到的那样,如果用$!查询最近的PID,它将返回子shell的PID,不完全是tail命令PID(5695),而是tail的父PID(5694,PPID)。我正在研究一种使用此 PPID(5694) 获取其子进程 tail(5695) 的方法,例如: $ ps -ef UID PID PPID TTY STIME COMMAND me 5695 5694 pty0 16:18:53 /usr/bin /tail me 5694 1 pty0 16:18:53 /usr/bin/bash
  • 嗨,Alok,作为测试并由 jerch 确认,也基于您的 cmets,更新以接受正确的解决方案
  • 在这种情况下,您可以尝试向尾部本身添加超时,例如( timeout 300s tail -n 1 -f "running.log")
猜你喜欢
  • 1970-01-01
  • 2014-10-05
  • 2016-12-29
  • 1970-01-01
  • 1970-01-01
  • 2013-06-02
  • 2012-10-08
  • 2022-01-05
相关资源
最近更新 更多