我正在运行以下脚本:
#!/bin/bash
ps ax | grep -q [v]arnish
if [ $? -eq 0 ];then
echo varnish is running...
exit 0
else
echo "Critical : varnish is not running "
exit 2
fi
输出就像::
[root@server ~]# sh -x check_varnish_pro.sh
+ ps ax
+ grep -q '[v]arnish'
+ '[' 0 -eq 0 ']'
+ echo varnish is running...
varnish is running...
+ exit 0
当我在命令行中运行相同命令时,我得到的退出状态为 1:
[root@server ~]# ps ax | grep -q [v]arnish; echo $?
1
这种情况就像服务器中没有安装varnish一样。该脚本在安装了 varnish 的服务器中运行良好。
为什么使用脚本和命令行运行时退出状态不同?如何改进这个脚本?
答案1
一般来说,尝试使用简单的方法来确定给定进程是否正在运行是一个坏ps
主意grep
。
你最好使用pgrep
以下方法:
if pgrep "varnish" >/dev/null; then
echo "Varnish in running"
else
echo "Varnish is not running"
fi
请参阅手册pgrep
。在某些系统上(可能不在 Linux 上),您会得到一个-q
与同一标志相对应的标志,从而grep
无需重定向到/dev/null
.还有一个-f
标志可以在完整的命令行上执行匹配,而不仅仅是进程名称。还可以将匹配限制为属于使用 的特定用户的进程-u
。
安装后pgrep
您还可以访问它,pkill
从而可以根据进程的名称向进程发出信号。
还,如果这是一个服务守护进程,如果您的 Unix 系统有一种方法来查询它的信息(例如,它是否已启动并正在运行),那么这就是恰当的检查它的方法。
在 Linux 上,您有systemctl
(systemctl is-active --quiet varnish
如果正在运行,则返回 0,否则返回 3),在 OpenBSD 上,您有rcctl
,等等。
现在到你的脚本:
在您的脚本中,您解析 的输出ps ax
。此输出将包含脚本本身的名称 ,check_varnish_pro.sh
其中显然包含字符串varnish
。这会给您带来误报。如果您在测试时在没有-q
标志的情况下运行它,您会发现这一点。grep
#!/bin/bash
ps ax | grep '[v]arnish'
运行它:
$ ./check_varnish_pro.sh
31004 p1 SN+ 0:00.04 /bin/bash ./check_varnish_pro.sh
另一个问题是,尽管您尝试通过在模式中使用来“隐藏”grep
进程,使其不被自身检测到。如果您碰巧在其中包含指定文件或目录的目录中运行脚本或命令行,则该方法将失败(在这种情况下,您将再次得到误报)。这是因为该模式未加引号,并且 shell 将使用它执行文件名通配。grep
[v]
varnish
看:
bash-4.4$ set -x
bash-4.4$ ps ax | grep [v]arnish
+ ps ax
+ grep '[v]arnish'
bash-4.4$ touch varnish
+ touch varnish
bash-4.4$ ps ax | grep [v]arnish
+ ps ax
+ grep varnish
91829 p2 SN+p 0:00.02 grep varnish
文件的存在varnish
将导致 shell 替换[v]arnish
为文件名varnish
,并且您会在进程表(进程)中找到模式grep
。
答案2
check_varnish_pro.sh
当您运行名为test 的脚本时
ps ax | grep -q [v]arnish
成功是因为有一个名为check_
漆_pro
跑步。
答案3
@AlexP 解释说非常简洁地描述了实际发生的情况,但是@Kusalananda 的想法将pgrep
/pkill
用于关键过程是强烈劝阻。更好的解决方案包括:
- 询问服务是否正在运行。
systemctl status varnishd
应该在现代 *nix 安装上解决这个问题。 如果在某些不幸的情况下您没有可用的服务,您可以简单地更改启动脚本以在进程退出时立即报告问题:
varnish || true some_command_to_send_an_alert_that_the_service_has_died
- 或者将启动服务的脚本更改为记录PID,然后使用 定期检查状态
kill -0 "$pid"
。