在bash脚本中,我想做以下事情(在伪代码中):
if [ a process exists with $PID ]; then
kill $PID
fi
条件语句的合适表达式是什么?
在bash脚本中,我想做以下事情(在伪代码中):
if [ a process exists with $PID ]; then
kill $PID
fi
条件语句的合适表达式是什么?
当前回答
例如,在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。
其他回答
看起来你想要
wait $PID
当$pid结束时返回。
否则你可以使用
ps -p $PID
检查进程是否仍然活跃(这比kill -0 $pid更有效,因为即使你不拥有pid,它也会工作)。
我从@FDS的回答中学习并点赞,因为它很好也很正确。但是,这里有一个我觉得更容易阅读和理解的表格。
所以,这是我最喜欢的版本:
解释:
The "$?" part means "the exit or return code from the previous command". The ps --pid "$pid" command returns exit code 0 if the specified PID ("$pid") is running, and some other number if not. Doing > /dev/null discards all output printed to stdout, since we don't want to see it. Rather, all we want is the exit code ("$?") from the ps --pid "$pid" command to see if that PID is running. More specifically, using > /dev/null redirects stdout output to the /dev/null pseudofile, whose purpose is to discard all incoming input.
pid=1234
ps --pid "$pid" > /dev/null
if [ "$?" -eq 0 ]; then
echo "PID $pid exists and is running."
fi
运行shellcheck path/to/this_script.sh告诉我,我实际上应该以另一种方式(如@FDS所示)来避免冗余。请看shellcheck输出:
eRCaGuy_hello_world/bash$ shellcheck check_if_pid_exists.sh
In check_if_pid_exists.sh line 46:
if [ "$?" -eq 0 ]; then
^--^ SC2181: Check exit code directly with e.g. 'if mycmd;', not indirectly with $?.
For more information:
https://www.shellcheck.net/wiki/SC2181 -- Check exit code directly with e.g...
尤其要注意这部分:
SC2181:直接用例如。'if mycmd;',而不是间接使用$?
查看此错误代码的完整描述:https://github.com/koalaman/shellcheck/wiki/SC2181。
因此,shellcheck推荐这样的表单:
pid=1234
if ps --pid "$pid" > /dev/null; then
echo "PID $pid exists and is running."
fi
如果你想适应那样做,那就去做吧。但是,如果你更喜欢我的方法,因为你认为我的方法更容易阅读和理解,那么你可以选择在上面添加# shellcheck disable=SC2181来禁用shellcheck警告,就像这样:
这是我最终的和首选的答案
ps --pid "$pid" >/dev/null
# shellcheck disable=SC2181
if [ "$?" -eq 0 ]; then
echo "PID $pid exists and is running."
else
echo "PID $pid does NOT exist."
fi
然而,这里的关键是永远不要在被检查的命令(在本例中为ps)和使用“$?”检查错误代码之间插入任何命令,甚至不要插入echo或print语句,否则检查错误代码将意外地检查来自最新命令的错误代码,例如插入的echo或print语句,而不是来自感兴趣的命令(在本例中为ps)!
这就是shellcheck推荐它们所做的工作的主要原因:它们希望确保您正在检查正确命令的错误代码。
除此之外,它只是一个迂腐的基于意见的讨论——相当于C中关于如何检查NULL(空指针)值的争论:
// The way preferred by pedantic people who don't want to "be redundant" with
// an "unnecessary" `== NULL` check:
if (!some_ptr)
{
printf("ERROR: null ptr.\n");
return;
}
// Versus the more-readable and understandable way which I prefer to use
// whenever my peers will approve it without a fight or long argument
if (some_ptr == NULL) // in C
// if (some_ptr == nullptr) // in C++
{
printf("ERROR: null ptr.\n");
return;
}
// Note: I just want to get my code merged and move on with life, so if they
// won't easily approve my preferred version above, I'll switch to the other,
// more-pedantic version of code to try to get a quick approval so I can be
// more productive.
// There are few things more discouraging than being blocked over
// silly "pedantry" when your code is correct, bug-free, well-written, and does
// what it says it does.
因此,就像在C中选择哪种方式检查NULL值(NULL ptrs)纯粹是个人喜好一样,在bash中选择哪种方式检查错误代码/返回代码也纯粹是个人喜好。目前,我更喜欢上面的版本,我已经标记为“我最终和首选的答案”。
总之,这是一个完整的、可运行的程序
从我的eRCaGuy_hello_world repo 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
# shellcheck disable=SC2181
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.
您可以通过首先运行ps aux并选择一个PID传递给它来找到要发送到脚本的有效PID(进程id)。
相关的
我的回答如何在bash等待几个子进程完成,并返回退出码!=0时,任何子进程结束code !=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。
最好的方法是:
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
and
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文件怎么办?
在这里,我将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存在,但被不同的应用程序使用,这可能会导致“不可预见的后果”。