在我的 Linux 启动脚本中,当我启动一个类似的进程时(此示例中使用了 openvpn,但该问题对于任何进程而言都具有普遍性);
openvpn --config /etc/myserver.conf
找到它并 100% 确定它是正确的进程并在停止部分将其终止的最佳方法是什么?我通常使用类似的东西:
pid=$(ps -efww | grep -v grep | grep openvpn | grep /etc/myserver.conf | awk '{print $2}')
当然,它几乎所有的时间都有效,但有时会出现意外匹配具有几乎相同名称的进程的问题(例如myserver.conf-new),所以我正在寻找更好的方法。
- 有些进程有办法将 pid 存储在某处,这很好,但一般来说,我对仅基于某个文件中的 pid 来终止进程持怀疑态度。
- Solaris 有项目,以我有限的经验来看,这并非一帆风顺,因为您必须先设置 /etc/projects,但它确实使标记和随后查找进程变得容易。
- 也许使用环境,例如设置环境变量(如 (MYID=myserver)),然后使用
ps e -ef | grep MYID=myserver
? 查找它。意外匹配仍可能造成同样的问题。
我希望有一些简单的事情,例如:
launch --tag myserver openvpn --config /etc/myserver.conf
和
pgrep --tag myserver
答案1
感谢@Iain、@KyleSmith 和@M_1 的回答,感谢你们帮助我开始使用 Server Fault。如果我在这里有更多声誉,我会给你们 +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
关键点是:
- 使用 md5sum(不太可能意外匹配)作为标签
- 在每个服务的启动脚本中使用不同的标签
- 查询 /proc/*/environ 以获取正在运行/相关/标记的进程的准确列表
- 使用使用 \b 进行 grep匹配单词边界以确保精确匹配
我不确定我是否喜欢污染环境,但我不知道有任何其他方法(例如 Solaris 项目)可以以任意方式标记 Linux 进程,以便我可以稍后向内核询问。至少,/proc/<pid>/environ 似乎反映启动时的环境,并且不受启动后进程可能发生的任何变化的影响,这表明这应该是可靠的,但是,这可能会发生意外变化。这可能在 Linux 之外起作用,也可能不起作用,具体取决于操作系统的 /proc 和 grep 实现。
我想我会尝试一段时间,看看效果如何。
答案2
不要害怕 pidfile,它们是经过验证的,并且通常由 root 拥有!:)
大多数发行版使用标准函数或二进制文件来启动守护进程并将生成的 PID 存储在文件中。例如,在 Debian 中,您可以使用带有选项的 start-stop-daemon --pidfile
。其他发行版有/etc/rc.d/init.d/functions
(或类似)用于启动守护进程的脚本。检查发行版中包含的一些更通用的启动脚本。
答案3
一个好主意是使用一个简单的 bash 包装脚本,该脚本写入该应用程序的锁/pid 文件(通常用于 Web 服务器或数据库),然后在需要时使用该文件来终止这一进程。
答案4
特别是对于 openvpn,你可以使用--writepid /path/to/file
命令行选项,例如
/usr/sbin/openvpn --writepid /var/run/openvpn/server.pid --config /etc/myserver.conf ...
这会将 openvpn 主进程的 PID 写入命名文件。
一般来说,你可以将程序包装在一个小脚本中,并使用 bash$!
内置变量将 pid 写入文件
#!/bin/bash
yourcommand &
echo $! >/path/to/pid.file