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

Bash 如何检查进程id(PID)是否存在,bash,process,pid,Bash,Process,Pid,在bash脚本中,我希望执行以下操作(在伪代码中): 条件语句的合适表达式是什么?我认为这是一个糟糕的解决方案,它为竞争条件打开了大门。如果进程在测试和调用kill之间终止,该怎么办?那么杀戮就会失败。那么,为什么不在所有情况下都尝试kill,并检查其返回值以了解其运行情况呢?ps命令和-p$PID可以做到这一点: $ ps -p 3531 PID TTY TIME CMD 3531 ? 00:03:07 emacs 要检查是否存在进程,请使用 kill

在bash脚本中,我希望执行以下操作(在伪代码中):


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

我认为这是一个糟糕的解决方案,它为竞争条件打开了大门。如果进程在测试和调用kill之间终止,该怎么办?那么杀戮就会失败。那么,为什么不在所有情况下都尝试kill,并检查其返回值以了解其运行情况呢?

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

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

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

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
你有两种方法:

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

[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
if [ -f /proc/$PID/exe ]; 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 [ ps aux | awk '{print $2 }' | grep -q $PID 2> /dev/null ]; then
    kill $PID 
fi
if [ -f /proc/$PID/exe ]; then
    kill $PID 
fi
顺便说一句:
kill-9$PID | | true
有什么问题


编辑:

考虑了几个月后。。(大约24…)我在这里给出的最初想法是一个不错的破解,但非常不可移植。虽然它教授了Linux的一些实现细节,但它将无法在Mac、Solaris或*BSD上工作。它甚至可能在未来的Linux内核上失败。请使用其他回复中所述的“ps”。

最好的方法是:

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

对于普通用户,有一个不可区分(非零)的退出代码,但init进程(PID 1)肯定正在运行

讨论 如果测试的主体是“杀死”,那么讨论杀死和种族条件的答案是完全正确的。我是来找“如何在bash中测试PID的存在性”这篇文章的

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

这似乎是您想要的

wait $PID
$pid
完成时返回

否则,您可以使用

ps -p $PID
检查进程是否仍处于活动状态(这比
kill-0$pid
更有效,因为即使您没有pid,它也会工作)


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

例如,在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的名称。

在这里,我将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
#/bin/bash
if[-f.pid];然后
读取pid<.pid
echo$pid
ps-p$pid>/dev/null
r=$?
如果[$r-等式0];然后
echo“$pid当前正在运行,未执行$0两次,正在退出…”
出口1
fi
fi
echo$$>.pid
#在这里做事
rm.pid

注意:存在竞争条件,因为它不检查pid的调用方式。如果系统重新启动并且.pid存在,但被其他应用程序使用,这可能会导致“不可预见的后果”。

pgrep [pid] >/dev/null
pgrep -u [user] -x [name] >/dev/null
通过名称

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

-x”表示“完全匹配”。

+1不幸的是,kill(1)的退出代码没有区分不同的错误情况(看起来它为每个未发出信号的进程增加一个退出值)。如果OP不介意编写他们自己的kill(2)包装器,他可以让它在kill(2)调用失败后,根据ERRNO的值以不同的值退出。目前我只是在执行kill-9,没有检查-如果它不存在,我只会得到一个错误“process not exist”,这不是很整齐。我该如何测试发生了什么?不要不小心
kill-9
。这会立即扼杀整个过程,使其没有机会自行清理。改为使用
kill
,这相当于
kill-15
。如果这不起作用,您应该找出原因,并且仅作为最后手段,使用
kill-9
kill
有点命名错误,因为它不一定会终止进程。它只是向进程发送一个信号
kill$PID
相当于
kill-15$PID
,它向进程发送信号15,SIGTERM,这是一条终止指令。没有信号0,这是一个特殊值,告诉
kill
只检查信号是否可以发送到进程,这在大多数情况下或多或少等同于检查它是否存在。请参阅,问题在于,如果进程不属于正在运行的用户,则您可能没有调用kill-0的权限。最好使用ps-p$PID>/dev/null 2>&1,它允许您查看进程状态,即使您没有发送信号的权限。@mckoss:在这种情况下,他无论如何也不能杀死它。因此,我猜-要使用
kill-0
,实际上我必须这样做:
kill-0 25667;echo$?
-然后如果我得到一个
0
返回,那么可以终止具有该PID的进程;如果进程PID(比如)不存在,
$?
将是
1
,表示失败。是这样吗?@sdau:请再读一遍。如果你无论如何都要杀了它,那就杀了它,否则你会有一个比赛条件。但是,是的,退出代码为0意味着当时可以向其发送信号。这并不意味着你可以肯定