使用设置的进程名称或 ID 将函数作为进程运行

使用设置的进程名称或 ID 将函数作为进程运行

我设置了一个 bash 脚本来监视多个 UDP 流并将其转换为可操作的数据。我的问题是我需要将脚本设置为定期检查流捕获是否正在运行,如果没有运行则重新启动它。

挑战在于为每个流捕获创建新的进程名称或 ID,并检查它是否正在运行。

这是我所拥有的内容的淡化版本。我希望有人能告诉我我是否走在正确的道路上:

Subscriber () {
    processName="$1$2$4";
    echo "$processName";
    pgrep $processName;
    if [[ $? -ne 0 ]] ; then
        echo "Subcription for $1 with IP $2 not found, restarting." ;
        while read -re -t 43200 doc; do
            <Code to analyze stream>
            done < <(bash -c "exec -a $processName <Commands to capture stream as JSON doc>")
    else
        echo "Subcription for $1 wtih IP $2 found to be running, skipping." ;
    fi
}
while read line; do
    Subscriber $line;
done < $flatFile

理想情况下,我想获取 exec -a 之后列出的整个命令字符串的进程 ID 或名称,但它目前只接受第一个命令,这似乎有点工作,但我不相信它会做我想让它做的事。

flatFile 参考是一个动态更新的平面文件,列出了我正在监视的数百个流。

答案1

Linux 上的进程名称至少会在进程每次执行命令时更改,但会更改为所执行文件的基本名称,而不是argv[0]bash 允许传递exec -a.

pgrep可以在 arg 列表(用空格连接)上与选项匹配-f,但请注意,像 for 一样greppgrep进行r常规e表达式匹配,因此您需要构造一个正则表达式来匹配argv[0]您想要的。

或者您可以确保传递的名称exec -a不包含正则表达式字符(包括.IPv4 地址中常见的字符)。

Subscriber () {
  process_arg0="$1$2$4"

  # change all regex operators and space to _
  process_arg0="${process_arg0//[][ .\\+?\$^()*{\}]/_}"

  printf>&2 '%s\n' "$process_arg0"
  if ! LC_ALL=C pgrep -f "^$process_arg0( |\$)"; then
    printf>&2 '%s\n' "Subscription for $1 with IP $2 not found, restarting."
    while IFS= read -r -t 43200 doc; do
      <Code to analyze stream>
    done < <(
      exec -a "$process_arg0" <Commands to capture stream as JSON doc>
    )
  else
    printf>&2 '%s\n' "Subscription for $1 with IP $2 found to be running, skipping."
  fi
}

(还删除了一些其他明显的错误,例如未加引号的引号、 的使用echo、 的无意义-e选项read、 缺少IFS=read解释器代码中嵌入的变量数据)。

无论如何,通过名称或参数列表匹配进程是非常脆弱和危险的,因为任何进程都可以为自己分配它们想要的任何名称或参数列表,并且这里使用的方法引入了竞争条件。使用适当的进程监督者/主管,例如您的 init 系统(systemdupstart和 co)或专用工具,例如runitdaemontoolssupervisorstart-stop-daemon可能更合适。

相关内容