为什么我的ps退出状态不同?脚本中的grep?


11

我正在以下脚本中运行:

#!/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

情况就像服务器上未安装清漆。该脚本在安装了清漆的服务器上运行良好。

为什么使用脚本和命令行运行时退出状态不同?如何改善这个脚本?


使用真实的过程监控系统,而不是这种黑客。几乎可以肯定,您的操作系统将具有一种内置方法,以确保您要保留的守护程序在发生故障时自动重新启动,无论是upstart,daemontools,systemd,launched还是众多其他替代方法之一。所有这些都将比这种手摇式黑客更强大和更强大。
查尔斯·达菲

Answers:


10

运行名为check_varnish_pro.sh测试的脚本时

ps ax  | grep -q [v]arnish

成功,因为正在运行一个名为check_varnish的脚本_pro


14

通常,尝试使用简单方法psgrep确定给定进程是否正在运行是个坏主意。

使用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上,您具有systemctlsystemctl 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过程以免被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将导致外壳程序[v]arnish用文件名替换,varnish并且您会在进程表(grep进程)中找到模式。


4
因为所有内容都是“在Linux环境中”的文件。
zee

@ z_-不太清楚它的连接方式,但是即使在非Linux Unices上也是如此。
库萨兰南达

4
不仅是grep进程;脚本的命名check_varnish_pro.sh也是一个因素。
TNW

@TNW我起初没有发现,但是您是对的。我要补充的是英寸
Kusalananda

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"

我同意,我只是在解决该问题的Shell脚本方面。注意,systemctl尽管如此,它几乎仅在Linux(AFAIK)上可用,而并非在所有现代的类似Unix的系统上可用。
Kusalananda

最初的问题带有标签“ linux”。我不确定为什么@muru将其删除。
l0b0

谢谢l0b0。我有两个问题“为什么”和“如何改进”。@AlexP的答案解决了我的第一个问题,而您的答案是第二个问题的更好解决方案。但是Kusalananda解释了与此相关的事情,我认为这对有类似问题的人会有所帮助。因此,我现在很困惑应该接受哪个答案。
prado

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.