![Bash 方法来检查进程是否已经在后台运行(并据此跳过重新执行)?](https://linux22.com/image/32809/Bash%20%E6%96%B9%E6%B3%95%E6%9D%A5%E6%A3%80%E6%9F%A5%E8%BF%9B%E7%A8%8B%E6%98%AF%E5%90%A6%E5%B7%B2%E7%BB%8F%E5%9C%A8%E5%90%8E%E5%8F%B0%E8%BF%90%E8%A1%8C%EF%BC%88%E5%B9%B6%E6%8D%AE%E6%AD%A4%E8%B7%B3%E8%BF%87%E9%87%8D%E6%96%B0%E6%89%A7%E8%A1%8C%EF%BC%89%EF%BC%9F.png)
如果进程尚未运行(在后台),我可以创建一个仅运行特定命令的 bash 命令行吗?
如何检查*命令是否已在运行?
(所以我可以在它们之间添加下一个命令,&&
这样下一个命令仅在第一个命令为真时才执行)。
*:测试、确定、发现、发现
答案1
答案2
我时常使用这种技术:
$ pgrep <process name> || <process name>
在此之前,pgrep
它曾经是这样完成的:
$ ps -eaf | grep -q <[p]rocess name> || <process name>
例子
带有 的位[p]
使得grep
不会因此而发现自己。
$ ps -eaf | grep -q [s]leep || sleep 10
答案3
这可能很棘手,因为您可以拥有独立运行的同一进程的不同实例。例如,服务器侦听不同的端口,或者以不同用户身份运行的服务。为了区分这些实例,您需要为每个实例分配一个唯一的标签。标签通常是一个文件,但它可以是抽象命名空间中的本地套接字、TCP 端口等——任何唯一标识符都可以。当标记是文件时,它可以是包含进程 ID(pidfile)的常规文件,或者文件正在侦听的命名管道或套接字等。理想情况下,标记是允许客户端连接的通信端点到那个过程。
每种不同类型的标签都会以不同的方式检查您正在查找的实例是否已启动并正在运行。例如,使用本地文件套接字,尝试连接到它,如果没有进程正在侦听该套接字,则启动该进程。如果标记是 pidfile,请检查是否存在具有该进程 ID 的进程,但请注意,这是脆弱的,因为如果该进程已死亡,则可能有一个不相关的进程重用了其 ID。请注意,如果两个客户端尝试在短时间内访问该进程,他们可能都会发现该进程不存在,并且都尝试启动它;正确地防止这种竞争条件可能很棘手。
当实例全部由同一主管进程启动时,管理实例会更容易,并且该主管进程会检测实例何时终止并做出相应反应。许多服务监控程序可以做到这一点。
如果程序在已知的通信端点上没有响应,并且不受管理程序管理,那么这个可怜人的标签就是 pidfile:一个包含进程 ID 的文件。当启动该进程时,将 pid 写入具有预先安排的名称的文件中。当您需要进程存在时,读取pid文件并查看是否存在具有该pid的进程。当您终止该进程时,请删除 pidfile。无监督 pidfile 最突出的问题是,如果进程终止,其 pid 可能会被某些不相关的进程重用。您至少应该检查进程名称或进程可执行文件,以确保您正在与正确的进程进行通信。许多 UNIX 变体都有一个正则表达式命令:pgrep SOMENAME
列出名称包含 SOMENAME 作为子字符串的进程,并提供附加选项来限制特定用户、要求精确匹配、更改使用“进程名称”的几种可能概念中的哪一个等。
答案4
其他选项:
pgrep -xq processname
- 仅匹配 GNU/Linux 中的前 15 个字符
- 不包括 OS X 上的祖先
ps -eo comm= | sed 's|.*/||' | grep -xq processname
- 仅匹配 GNU/Linux 中的前 15 个字符
sed 's|.*/||'
删除 OS X 上的目录名部分
在 GNU/Linux 中,ps -o comm
将命令名称截断为 15 个字符,pgrep
并且ps -C
仅匹配前 15 个字符。
ps -C
OS X 不支持(匹配命令名称)。
在 OS X 中ps -o comm
打印命令的绝对路径并且ps -co comm
仅打印命令名称。在 GNU 中ps -o comm
仅打印命令名称并且-c
具有不同的含义。
OS X 的 pgrep 不包含没有-a
. GNU 的 pgrep 默认包含它们,但不支持-a
.
grep -x
并且pgrep -x
不暗示,因此如果进程名称可以包含正则表达式字符,则-F
使用。-Fx