尝试编写一个 shell 脚本来远程测试服务器,但是当我注销时它一直在 else 语句中

Vas*_*914 9 linux grep shell-script ping bourne-shell

尝试在这里编写一个 shell 脚本,它不断测试我的服务器并在它出现故障时给我发送电子邮件。

问题是,当我从 ssh 连接注销时,尽管&在命令末尾运行它,例如./stest01.sh &,它会自动落入 else 并不间断地向我发送邮件,直到我再次登录并杀死它。

#!/bin/bash
while true; do
    date > sdown.txt ;
    cp /dev/null pingop.txt ;
    ping -i 1 -c 1 -W 1 myserver.net > pingop.txt &
    sleep 1 ;
    if
        grep "64 bytes" pingop.txt ;
    then
        :
    else
        mutt -s "Server Down!" myemail@address.com < sdown.txt ;
        sleep 10 ;
    fi
done
Run Code Online (Sandbox Code Playgroud)

Kus*_*nda 20

当 GNUgrep尝试写入其结果时,它将失败并显示非零退出状态,因为它无处可写输出,因为 SSH 连接已消失。

这意味着if语句总是采用else分支。

为了说明这一点(这与您的情况不完全相同,但它显示了如果 GNUgrep无法写入其输出会发生什么):

$ echo 'hello' | grep hello >&- 2>&-
$ echo $?
2
Run Code Online (Sandbox Code Playgroud)

这里我们grepecho产生的字符串,但我们关闭了两个输出流,grep以便它不能在任何地方写入。如您所见,GNU 的退出状态grep是 2 而不是 0。

这是 GNU 特有的grepgrep在 BSD 系统上不会表现相同:

$ echo 'hello' | grep hello >&- 2>&-    # using BSD grep here
$ echo $?
0
Run Code Online (Sandbox Code Playgroud)

要解决此问题,请确保脚本不生成输出。您可以使用exec >/dev/null 2>&1. 此外,我们应该使用grep它的-q选项,因为我们对查看它的输出根本不感兴趣(这通常也会加快速度,grep因为它不需要解析整个文件,但在这种情况下,它的作用很小由于文件很小,因此速度差异)。

简而言之:

$ echo 'hello' | grep hello >&- 2>&-
$ echo $?
2
Run Code Online (Sandbox Code Playgroud)

您也可以ping直接使用测试,从而消除对其中一个中间文件的需要(并且还摆脱了另一个真正只包含日期戳的中间文件):

$ echo 'hello' | grep hello >&- 2>&-    # using BSD grep here
$ echo $?
0
Run Code Online (Sandbox Code Playgroud)

在上述脚本的两种变体中,我选择在无法到达主机时退出循环,以尽量减少发送的电子邮件数量。如果您希望服务器最终再次启动,您可以改为break使用 egsleep 10m或其他东西替换。

我还稍微调整了使用的选项pingas-i 1-c 1.

较短(除非您希望它在主机无法访问时继续发送电子邮件):

#!/bin/sh

# redirect all output not redirected elsewhere to /dev/null by default:
exec >/dev/null 2>&1

while true; do
    date >sdown.txt

    ping -c 1 -W 1 myserver.net >pingop.txt

    if ! grep -q "64 bytes" pingop.txt; then
        mutt -s "Server Down!" myemail@address.com <sdown.txt
        break
    fi

    sleep 10
done
Run Code Online (Sandbox Code Playgroud)

作为每分钟运行的 cron 作业(如果服务器继续停机,将继续每分钟发送电子邮件):

* * * * * ping -q -c 1 -W 1 >/dev/null 2>&1 || ( date | mail -s "Server down" myemail@address.com )
Run Code Online (Sandbox Code Playgroud)

  • 通过在开头附近添加 `exec &lt;/dev/null &gt;/dev/null 2&gt;&amp;1` 将整个脚本的所有内容重定向到 /dev/null 可能更安全。这样,如果例如`ping` 决定向stderr 写一些东西,它就不会引起问题。 (4认同)