在 bash 脚本中,我想执行以下操作(在伪代码中):
if [ a process exists with $PID ]; then
kill $PID
fi
条件语句的适当表达式是什么?
最好的方法是:
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 $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
文件命名为别的东西怎么办?
要检查进程是否存在,请使用
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
ps
命令-p $PID
可以做到这一点:
$ ps -p 3531
PID TTY TIME CMD
3531 ? 00:03:07 emacs
你有两种方法:
让我们首先在我的笔记本电脑中寻找一个特定的应用程序:
[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 ......)我在这里给出的最初想法是一个很好的 hack,但非常不便携。虽然它教授了一些 Linux 的实现细节,但它无法在 Mac、Solaris 或 *BSD 上运行。它甚至可能在未来的 Linux 内核上失败。请按照其他 回复中的说明使用“ps” 。
好像你想要
wait $PID
完成后将返回$pid
。
否则你可以使用
ps -p $PID
检查进程是否还活着(这比kill -0 $pid
因为即使你不拥有 pid 它也能工作更有效)。
我认为这是一个糟糕的解决方案,它为竞争条件开辟了道路。如果进程在您的测试和您调用 kill 之间终止怎么办?然后杀死将失败。那么为什么不在所有情况下都尝试杀死,并检查它的返回值以了解它是如何进行的呢?
例如,在 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:
pgrep [pid] >/dev/null
按名称:
pgrep -u [user] -x [name] >/dev/null
“ -x ”表示“完全匹配”。
在这里,我将 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 存在但被不同的应用程序使用,这可能会导致“不可预见的后果”。
我从@FDS 的答案中学习并投票赞成,因为它很好而且正确。但是,这里有一个我觉得更容易阅读和理解的表格:
pid=1234
ps --pid "$pid" > /dev/null
if [ "$?" -eq 0 ]; then
echo "PID $pid exists and is running."
fi
更新:shellcheck check_if_pid_exists.sh
告诉我实际上应该以另一种方式(如@FDS 所示)以避免冗余:
pid=1234
if ps --pid "$pid" > /dev/null; then
echo "PID $pid exists and is running."
fi
所以……也许我以后会适应那样做。
无论如何,这是一个完整的、可运行的程序(我想这是我在这里的贡献):
check_if_pid_exists.sh:
#!/usr/bin/env bash
pid=1234
if [ "$#" -gt 0 ]; then
# At least 1 argument was passed in, so assume it is the PID
pid="$1"
fi
# Try to print the process (`ps`) information for this PID. Send it to
# /dev/null, however, so we don't actually have to look at it. We just want
# the return code, `$?`, which will be 0 if the process exists and some other
# number if not.
ps --pid "$pid" > /dev/null
if [ "$?" -eq 0 ]; then
echo "PID $pid exists and is running."
else
echo "PID $pid does NOT exist."
fi
示例运行调用和输出:
eRCaGuy_hello_world/bash$ ./check_if_pid_exists.sh 28876
PID 28876 exists and is running.
eRCaGuy_hello_world/bash$ ./check_if_pid_exists.sh
PID 1234 does NOT exist.
eRCaGuy_hello_world/bash$ ./check_if_pid_exists.sh 5678
PID 5678 does NOT exist.