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


184

在bash脚本中,我想执行以下操作(使用伪代码):

if [ a process exists with $PID ]; then

    kill $PID 

fi

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

Answers:


182

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

kill -0 $pid

但是正如@unwind所说,如果您仍然要杀死它,

kill $pid

否则您将有比赛条件。

如果您想忽略的文本输出kill并根据退出代码执行某些操作,则可以

if ! kill $pid > /dev/null 2>&1; then
    echo "Could not send SIGTERM to process $pid" >&2
fi

1
查看手册页,kill -0是:“退出代码指示是否可以发送信号”。那么,这实际上杀死了一个进程,还是只是告诉您它是否可以被杀死?
理查德H

23
kill之所以被错误命名,是因为它不一定会终止该过程。它只是向过程发送信号。 kill $PID等价于kill -15 $PID,它向进程发送信号15 SIGTERM,这是终止指令。没有信号0,这是一个特殊的值,告诉kill您仅检查是否可以将信号发送到进程,在大多数情况下,这或多或少地等同于检查它是否存在。参见linux.die.net/man/2/killlinux.die.net/man/7/signal
ChristofferHammarström

43
这样做的问题是,如果该进程不属于运行中的用户,则您可能没有调用kill -0的权限。最好使用ps -p $ PID> / dev / null 2>&1,即使您没有发送信号的权限,也可以查看进程状态。
mckoss'4

6
@mckoss:在那种情况下,他无论如何也无法杀死它。
ChristofferHammarström'4

2
因此,我猜想- kill -0实际上,我必须这样做:kill -0 25667 ; echo $?-然后,如果我得到了0返回,则具有该PID的进程可以被杀死;如果过程PID(例如)不存在,$?则将为1,表示失败。那是对的吗?
sdaau

264

最好的方法是:

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

是即使pid正在运行并且您没有杀死它的权限,退出代码也将为非零。例如:

kill -0 1

kill -0 $non-running-pid

对于普通用户,其退出代码没有区别(非零),但是init进程(PID 1)肯定正在运行。

讨论

如果测试的主体是“杀人”,则讨论杀人和种族条件的答案是正确的。我来找一般的“ 您如何测试bash中的PID是否存在 ”。

/ proc方法很有趣,但是在某种意义上破坏了“ ps”命令抽象的精神,即,您不需要去查找/ proc,因为如果Linus决定调用其他“ exe”文件怎么办?


1
ps -p始终为我返回状态0
IttayD 2014年

1
ps -p ####在Ubuntu 14.04下对我来说效果很好,+ 1,谢谢!
Ligemer '16

3
ps -p始终在os x中返回状态代码0,因为当它与任何正在运行的进程都不匹配时,它会打印进程的空列表
Douglas Correa

我可以确认在macOS Sierra上可以正常工作。而且,-p至少在那种情况下,这是不必要的。ps $PID具有完全相同的结果。
user137369 '17

可移植性是避免使用/ proc的一个很好的理由,但是linux破坏其ABI并不是我特别担心的情况。
David Roundy

67
if [ -n "$PID" -a -e /proc/$PID ]; then
    echo "process exists"
fi

要么

if [ -n "$(ps -p $PID -o pid=)" ]

在后一种形式中,-o pid=是一种输出格式,仅显示没有标题的进程ID列。非空字符串运算符必须使用引号-n才能给出有效结果。


1
第二种方法也适用于Mac,这是附加的优点(Mac OS X没有/ proc FS)。但是,您可以避免使用子外壳,并在Mac和Linux上都使用它:if ps -p"$PID" -o "pid=" >/dev/null 2>&1; then echo "Process is running..."; fi
2015年

不幸的是,ps平台之间的选项和功能往往会有所不同,因此它仍然不是完全可移植的。
三胞胎

1
如果$PID为空,则[ -e /proc/$PID ]由于/proc/目录仍然存在,因此仍将返回true 。
Magne '18

34

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

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

11

您有两种方法:

让我们从在笔记本电脑中查找特定的应用程序开始:

[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。

第一种方式:在第二列中运行PID的“ ps aux”和grep。在此示例中,我寻找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部分似乎是错误的(不会杀死子
进程

为什么在使用第一种方法时会出现[:缺少`]'的问题?
tenmiles 2015年

1
/proc/$PID/exe不是常规文件。因此,[ -f /proc/$PID/exe ]将始终返回false结果。尝试[ -h /proc/$PID/exe ]
亚历山大·延查鲁克

8

好像你要

wait $PID

何时会返回 $pid完成。

否则你可以使用

ps -p $PID

来检查该进程是否仍然存在(这比kill -0 $pid因为即使您不拥有该pid 仍然有效,但效果更好)。


1
等待不是那么有效,因为进程应该是当前shell的子进程,否则它将给出:pid 123 is not a child of this shell
Calumah

7

我认为这是一个糟糕的解决方案,会在比赛条件下出现。如果该过程在您的测试和要求杀死之间死掉了怎么办?然后杀死将失败。那么,为什么不尝试在所有情况下都执行kill并检查其返回值以了解其执行情况呢?


不幸的是,+1 kill(1)的退出代码无法区分不同的错误情况(看起来好像它针对失败的每个进程将退出值增加1)。如果OP不介意编写自己的kill(2)包装器,则在kill(2)调用失败后,可以根据ERRNO的值使用不同的值退出它。
某人2010年

目前,我只是在不检查的情况下执行kill -9-我只是得到一个错误“进程不存在”,如果它不存在则不是很整洁。我将如何测试发生了什么?
理查德H

14
不要随便kill -9。这只是立即终止了该进程,因此没有机会自行清理。而是使用kill等效于kill -15。如果那行不通,您应该找出原因,并且只能作为最后的选择kill -9
ChristofferHammarström,2010年

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,但被其他应用程序使用,则可能导致“无法预料的后果”。


0

例如,在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不会返回负数,因为负PID毫无意义,并且您无法杀死init,因此您的条件是毫无意义的(此外,您需要转义>以防止其执行重定向)。您想检查结果是否为空,但是,当然,像其他任何不错的工具一样,pidof设置退出代码来告诉您它是否有效,因此正确的解决方案是- if Pid=$(pidof 'process_name'); then ...或(如果Pid以后不再需要该值)if pidof 'process_name'; then...
三胞胎

@tripleee是正确的,该pidof示例充满了对bash的test工作方式的误解。gnu.org/software/bash/manual/html_node/...
布鲁诺Bronosky

0

下面的代码检查我的进程是否正在运行,如果没有执行任何操作。

让我们仅在流程未运行时每小时检查一次来自Amazon SQS的新消息。

#!/bin/bash
PID=$(ps aux | grep '/usr/bin/python2.7 manage.py SES__boto3_sqs_read' | grep -v grep | awk '{print $2}')
if [[ -z $PID ]]; then
    /usr/bin/python2.7 /home/brian/djcode/proyectoONE/manage.py SES__boto3_sqs_read
else
    echo "do nothing, just smile =)"
fi
exit $?
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.