我有一堆以start.sh
脚本开头的命令,存储它们的 PID。然后,我想stop.sh
在用户方便的时候通过运行来阻止它们。
注意陷阱:
- 我今天运行,它将 PID 、、
start.sh
存储在文件中。15000
15001
15002
- 我忘记停止我的进程。一周后,我重新启动了计算机。
- 我现在运行脚本。它会尝试终止 PID 为、、
stop.sh
的任务,并无意识地从文件中读取它们。 => 如果在我新重启的系统上碰巧有这些 PID,这些任务就不再是我通过脚本启动的任务,我将使我的系统处于未知状态。15000
15001
15002
start.sh
当我在 Linux 脚本中首先捕获进程的 PID 时$$
,如何收集其他信息以确保我不会与将来可能出现的具有相同 PID 的另一个任务混淆?
例如,收集 PPID,或开始日期/时间,或确保某种“通用唯一性”的东西,如果我可以写这个..?
如何收集进程信息以及如何在不混乱的情况下杀死它?
答案1
如何收集进程信息以及如何在不混乱的情况下杀死它?
你不知道。
相反,您可以确保该流程在您稍后可以可靠地引用以再次找到它的上下文中运行。
这正确的处理这个问题的方法是使用目标平台的服务管理系统(现在通常是 Linux 系统上的 systemd)。他们在大多数情况下都会正确处理事情,并且特别设计的做这种事情。
按优先顺序降序排列的替代方案是:
- 用一个组组有一个具体的名字。这种方法是 Linux 特有的,但具有许多明显的好处,例如能够可靠地、原子地杀死全部您启动的进程的子进程。它们本质上解决了生命周期问题,因为特定进程与 cgroup 显式关联,而不是 PID 与 cgroup 关联。
- 使用监督系统,例如运行,s6, 或者守护进程工具。这些解决方案通过利用一个可以轻松可靠地定位的进程作为您要监视的进程的父进程来解决该问题。
- 将您的 PID 文件放入
/run
应在的位置。您指出的跨系统重新启动时 PID 重用的问题是一个已知问题,已得到可靠解决几十年只需将 PID 文件放入每次系统重新启动时都会被擦除的目录中。/run
是 Linux 系统上的标准位置。这仍然存在 PID 重用问题(因为 PID 仅在关联进程的生命周期内是唯一的,因此其中一个进程意外终止并留下 PID 文件可能仍会遇到重用问题)。
答案2
当我必须在大型网络上启动各种诊断脚本时,我让所有脚本接受(并忽略)一个--tag=....
选项。 (显然,您不能使用标准命令来执行此操作,但您可以将它们包装在父 shell 中)。
典型的 --tag 将包含(至少)启动它的主机名、随机数和启动时间(精确到纳秒)。对于远程任务,您甚至可能不知道远程系统上的 pid。
该ps
命令可以显示参数,以便您可以 grep 特定进程。您甚至可以有一个 cron 作业,定期生成潜在进程的报告,并从列表中清除那些已终止的进程。
答案3
将PID信息存储在tmpfs文件系统上,因此重新启动后,这些文件不存在。
/run
通常是 tmpfs,或者/tmp
在某些发行版上是 tmpfs。
或安装您自己的
# mount tmpfs /path/to/your/mountpoint -t tmpfs
答案4
将 start.sh 绑定安装/proc/15000
到某个其他目录。 (最好这由父进程在退出之前完成,wait
以避免竞争条件。)在 stop.sh 中,尝试打开您绑定安装的目录。如果绑定安装消失,则系统将重新启动。如果打开目录失败并显示 ESRCH(无此类进程),则进程退出。 (即使此后具有相同 PID 的新进程开始运行,也会发生这种情况。)如果打开目录成功并且绑定挂载仍然存在,那么它仍然是您的进程并且可以安全地终止。 (为了避免另一个竞争条件,最好pidfd_send_signal
杀死它。)