如何检查进程ID(PID)是否存在

246

在Bash脚本中,我想要执行以下操作(伪代码):

if [ a process exists with $PID ]; then

    kill $PID 

fi

条件语句的适当表达式是什么?


1
通过 路径:https://dev59.com/-4nca4cB1Zd3GeqP5xJz - Alberto Salvia Novella
2
按名称:https://askubuntu.com/questions/157779/how-to-determine-whether-a-process-is-running-or-not-and-make-use-it-to-make-a-c/1317605 - Alberto Salvia Novella
11个回答

346

最好的方式是:

if ps -p $PID > /dev/null
then
   echo "$PID is running"
   # Do something knowing the pid exists, i.e. the process with $PID is running
fi

kill -0 $PID 的问题在于,即使进程正在运行且您没有权限将其终止,退出代码也将为非零。例如:

问题在于 kill -0 $PID 命令不论进程是否正在运行,都会返回0作为成功的退出代码。因此,如果您要确保进程正在运行并且您有权限终止它,则应使用不同的方法。

kill -0 $known_running_pid

kill -0 $non_running_pid

有非零的退出代码,对于普通用户来说无法区分,但其中一个假设在运行,而另一个则没有。


部分相关的信息,由AnrDaemon提供:init进程(PID 1)肯定在所有Linux机器上运行,但不是所有POSIX系统都是Linux。在那里不能保证存在PID 1:

kill -0 1 
-bash: kill: (1) - No such process … 

讨论

如果测试主体是“终止”,那么讨论杀死和竞态条件的答案是完全正确的。我是来寻找关于如何在bash中测试PID存在性的一般性问题的。

/proc方法很有趣,但在某种程度上打破了 ps 命令的抽象层次,也就是说,您不需要查看 /proc ,因为如果Linus决定将 exe 文件改名,该方法可能会出现问题。


1
ps -p 始终对我返回状态 0。 - IttayD
1
ps -p #### 在我的 Ubuntu 14.04 上运行良好,谢谢! - akahunahi
3
在 macOS 中,当 ps -p 命令没有匹配到任何正在运行的进程时,它会打印一个空的进程列表并返回状态码 0。请注意,这里的翻译并未改变原意,只是将其转化为更易懂的中文表达方式。 - Douglas Correa
4
这在BusyBox上不起作用。OpenWrt仅识别w表示“宽输出”,Alpine仅使用-o来过滤输出列。文档 还提到通过使用-T来显示线程。没有-p参数。 - antichris
2
如果您想知道具有ID $PID的进程是否存在,只需执行test -d /proc/$PID而不是启动其他进程。请注意,您永远无法知道某个进程是否存在于另一个PID名称空间中。 - Mikko Rantalainen
显示剩余6条评论

213

要检查进程是否存在,请使用

kill -0 $pid

但就像@unwind所说的那样,如果你想让程序在所有情况下都终止,那么只需要

kill $pid
否则你会出现竞态条件,进程在第一个kill -0后可能已经消失。
如果您想忽略kill的文本输出并根据退出代码执行某些操作,则可以...
if ! kill $pid > /dev/null 2>&1; then
    echo "Could not send SIGTERM to process $pid" >&2
fi

38
“kill”这个命令名称有些不准确,因为它并不一定会杀死进程。它只是向进程发送一个信号。使用“kill $PID”等同于使用“kill -15 $PID”,它会向进程发送信号编号为15的SIGTERM信号,指示进程终止。并不存在信号0,它是一个特殊值,告诉“kill”只需检查是否可以向该进程发送信号,这在大多数情况下基本上等同于检查进程是否存在。参见http://linux.die.net/man/2/kill和http://linux.die.net/man/7/signal。 - Christoffer Hammarström
54
如果进程不是由当前用户拥有,那么调用 kill -0 可能会没有权限的问题。更好的方法是使用 ps -p $PID > /dev/null 2>&1,它允许您查看进程的状态,即使您没有权限发送信号也可以。 - mckoss
9
在这种情况下,他无论如何都不能杀死它。 - Christoffer Hammarström
4
因此,我想使用kill -0命令,实际上需要执行以下操作:kill -0 25667; echo $? - 然后如果返回值是0,则表示可以杀死该PID的进程;如果该进程PID(例如)不存在,则$?将为1,表示失败。这样正确吗? - sdaau
5
请再读一遍。如果你无论如何都要杀死它,那就直接杀了它,否则你将会遇到竞态条件。但是,是的,退出代码为0意味着此时有可能向其发送一个信号。这并不意味着你可以确定在一毫秒后就能向其发送一个信号。 - Christoffer Hammarström
显示剩余3条评论

91
在实现procfs接口的系统上,例如Linux,您只需检查/proc/$PID是否存在即可:
if test -d /proc/"$PID"/; then
    echo "process exists"
fi

否则,您可以使用 ps 程序:
if [ -n "$(ps -p $PID -o pid=)" ]

在后一种形式中,-o pid= 是一种输出格式,只显示进程ID列而无标题。引号对于非空字符串操作符 -n 来说是 必要的,以给出有效结果。

2
第二种方法也适用于Mac,这是一个额外的优点(Mac OS X没有/proc FS)。但是,您可以避免使用子shell并在Mac和Linux上使用此命令:if ps -p"$PID" -o "pid=" >/dev/null 2>&1; then echo "Process is running..."; fi - Will
不幸的是,“ps”选项和功能在不同平台之间存在差异,因此仍然不完全可移植。 - tripleee
3
如果$PID为空,则[ -e /proc/$PID ]仍将返回true,因为/proc/目录仍然存在。 - Magne
1
-e /proc/$PID/status 使 -n "$PID" 检查变得不必要,因为没有 /proc//status 文件。 - Maxim Egorushkin

42

ps 命令加上 -p $PID 可以做到这一点:

$ ps -p 3531
  PID TTY          TIME CMD
 3531 ?        00:03:07 emacs

13

你有两种方法:

让我们首先查找我笔记本电脑中的特定应用程序:

[root@pinky:~]# ps fax | grep mozilla
 3358 ?        S      0:00  \_ /bin/sh /usr/lib/firefox-3.5/run-mozilla.sh /usr/lib/firefox-3.5/firefox
16198 pts/2    S+     0:00  \_ grep mozilla

现在所有的例子都将查找PID为3358

第一种方法: 运行ps aux并使用grep来查找第二列中的PID。在这个例子中,我查找firefox,然后查找它的PID

[root@pinky:~]# ps aux | awk '{print $2 }' | grep 3358
3358

那么您的代码将是:

if [ ps aux | awk '{print $2 }' | grep -q $PID 2> /dev/null ]; then
    kill $PID 
fi

第二种方式:只需在/proc/$PID目录中查找某些内容。本示例中我使用了exe,但你也可以使用其他任何内容。

[root@pinky:~]# ls -l /proc/3358/exe 
lrwxrwxrwx. 1 elcuco elcuco 0 2010-06-15 12:33 /proc/3358/exe -> /bin/bash

那么你的代码将会是:

if [ -f /proc/$PID/exe ]; then
    kill $PID 
fi

顺便问一下:kill -9 $PID || true有什么问题吗?


编辑:

经过大约24个月的思考...原来我给出的想法很巧妙,但是高度不可移植。虽然它教授了Linux的一些实现细节,但它在Mac、Solaris或*BSD上将无法工作。甚至可能在未来的Linux内核上失败。请使用其他答案中描述的“ps”。


至少 kill -9 部分似乎是错误的(不能杀死子进程) - nurettin
当我使用第一种方式时,为什么会出现“[: missing `]'”错误? - tenmiles
1
/proc/$PID/exe 不是一个普通的文件。因此,[ -f /proc/$PID/exe ] 将始终返回 false 结果。请尝试 [ -h /proc/$PID/exe ] - Alexander Yancharuk

8

看起来你想要

wait $PID

$pid完成时,将返回结果。

否则,您可以使用

ps -p $PID

检查进程是否仍在运行(这比kill -0 $pid更有效,因为即使您不拥有pid,它也可以工作)。


4
等待并不像将进程作为当前 shell 的子进程那样有效,否则会出现“pid 123 不是此 shell 的子进程”的错误提示。 - Calumah

8

我认为那是一个不好的解决方案,会导致竞态条件。如果进程在你的测试和kill调用之间死亡了,那么kill将失败。所以为什么不在所有情况下尝试kill,并检查其返回值以了解情况如何呢?


+1 不幸的是,kill(1) 的退出代码不能区分不同的错误情况(似乎它会为每个未能发送信号的进程递增退出值)。如果 OP 不介意编写自己的 kill(2) 包装器,他可以根据失败的 kill(2) 调用后 ERRNO 的值退出不同的值。 - just somebody
目前我只是使用kill -9命令,没有进行任何检查 - 如果进程不存在,我只会收到一个“进程不存在”的错误,这并不是很整洁。我该如何测试发生了什么? - Richard H
15
不要轻易地使用 kill -9 命令,它会立即杀死进程,并不给予进程清理自身的机会。相反,应该使用 kill 命令,它等效于 kill -15 命令。如果这不能解决问题,你应该找出原因,并只在万不得已时使用 kill -9 命令。 - Christoffer Hammarström

2
例如,在GNU/Linux中,您可以使用以下命令:
Pid=$(pidof `process_name`)

if [ $Pid > 0 ]; then

   do something
else

   do something
fi 

或者类似于这样的东西。
Pin=$(ps -A | grep name | awk 'print $4}')
echo $PIN

这将显示应用程序的名称,仅名称而不包括ID。


1
pidof does not return a negative number, as a negative PID does not make any sense, and you can't kill init, so your conditional makes no sense (and besides, you'd need to escape the > to prevent it from performing a redirection). You want to check for an empty result, but of course, like any decent tool, pidof sets an exit code to tell you whether it worked, so the proper solution is if Pid=$(pidof 'process_name'); then ... or (if you won't need the value in Pid later on) simply if pidof 'process_name'; then... - tripleee
@tripleee 是正确的,pidof 的例子充满了对 bash test 工作方式的误解。https://www.gnu.org/software/bash/manual/html_node/Bash-Conditional-Expressions.html - Bruno Bronosky

1

pid

pgrep [pid] >/dev/null

按照名称:

名称

pgrep -u [user] -x [name] >/dev/null

"-x" 的意思是“精确匹配”。

0

我将PID存储在名为.pid的文件中(类似于/run/...),仅当脚本未被执行时才执行。

#!/bin/bash
if [ -f .pid ]; then
  read pid < .pid
  echo $pid
  ps -p $pid > /dev/null
  r=$?
  if [ $r -eq 0 ]; then
    echo "$pid is currently running, not executing $0 twice, exiting now..."
    exit 1
  fi
fi

echo $$ > .pid

# do things here

rm .pid

注意:存在竞态条件,因为它不检查该pid是如何被调用的。如果系统重新启动并且.pid存在但被不同应用程序使用,则可能会导致“意想不到的后果”。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接