标记/识别进程以稍后杀死它们的最佳方法?

Ste*_*let 5 linux startup-scripts

在我的 linux 启动脚本中,当我启动一个进程时(本示例使用 openvpn,但问题对任何进程都是通用的);

openvpn --config /etc/myserver.conf
Run Code Online (Sandbox Code Playgroud)

找到它并100%确定它是正确的过程并在停止部分杀死它的最佳方法是什么?我通常使用类似的东西:

pid=$(ps -efww | grep -v grep | grep openvpn | grep /etc/myserver.conf | awk '{print $2}')
Run Code Online (Sandbox Code Playgroud)

当然它几乎一直都在工作,但有时会出现意外匹配名称几乎相同的进程(例如 myserver.conf-new)的问题,所以我正在寻找更好的方法。

  • 某些进程有办法将 pid 存储在某处,这很好,但通常我对仅基于某个文件中的 pid 杀死进程持怀疑态度。
  • Solaris 有项目,在我有限的经验中并不是所有的玫瑰,因为您必须先设置 /etc/projects,但它确实可以轻松标记并稍后查找进程。
  • 也许使用环境,比如设置一个像 (MYID=myserver) 这样的环境变量,然后用ps e -ef | grep MYID=myserver? 仍然可能会遇到意外匹配的相同问题。

我希望有一些简单的东西,比如:

launch --tag myserver openvpn --config /etc/myserver.conf
Run Code Online (Sandbox Code Playgroud)

pgrep --tag myserver
Run Code Online (Sandbox Code Playgroud)

Ste*_*let 7

感谢 @Iain、@KyleSmith 和 @M_1 的回答,并帮助我开始解决服务器故障。如果我在这里有更多代表,我会+1 你们。(编辑:现在我有代表,周围都是 +1)。

我将回答我自己的问题,因为我发现了一些可以满足我的需求的方法:避免与 ps 进行不精确模式匹配且不使用 pid 文件的通用解决方案。完全主观的是,这将是“最佳”方式,因为在 unix 中使用 pid 文件显然有着悠久而成功的历史,但是这是我明确表示由于各种原因我不喜欢的东西,这些是:它们可以正确创建很棘手,每个软件都不同,在每个发行版上都不同,可能会过时/覆盖,并且本质上不一定代表实际发生的事情。我宁愿使用某种进程标记,询问内核并获得真正的答案。

修剪的例子:

#!/bin/sh
_TAG=d726cc7fa57a308afdc057b228a13f6d
case "$1" in
start)
  _TAG=$_TAG ./self-backgrounding-process
  _TAG=$_TAG ./non-self-backgrounding-process &
  ;;
stop)
  pids=$(grep -l "\b_TAG=$_TAG\b" /proc/*/environ | cut -d/ -f3)
  [ -n "$pids" ] && kill $pids
  ;;
esac
Run Code Online (Sandbox Code Playgroud)

关键点是:

  • 使用 md5sum(不太可能被意外匹配的东西)作为标签
  • 在每个服务的启动脚本中使用不同的标签
  • 查询 /proc/*/environ 以获取运行/相关/标记进程的准确列表
  • 使用grep 和 \b来匹配单词边界以确保完全匹配

我不确定我是否喜欢污染环境,但我不知道有任何其他方式(例如 Solaris 项目)可以以任意方式标记 linux 进程,以便稍后向内核询问。至少, /proc/<pid>/environ 似乎反映了启动时的环境,并且不受进程可能在 之后进行的任何更改的影响,这表明这应该是可靠的,但是,这可能会发生意外更改。这可能会也可能不会在 Linux 之外工作,具体取决于操作系统的 /proc 和 grep 实现。

我想我会尝试一段时间,看看效果如何。