尝试编写可继续远程测试服务器的shell脚本,但注销时该脚本始终落在else语句中


9

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

问题是,当我从ssh连接注销时,尽管&在命令末尾(如)运行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

1
我不是bash专家,但是冒号:做什么?对我来说,这是一个分号;……
Ned64 '19

3
@ Ned64 :什么也不做。这就是它的目的。在这里,他们没有颠倒测试,而是使用它先进行无操作else
库萨兰达

@Kusalananda好,谢谢。以为是错字可以解释问题。
Ned64

1
我也感到困惑,为什么人们会尝试在注销后让Shell脚本继续运行。cron或systemd计时器不是更好的选择吗?
克里夫·阿姆斯特朗

Answers:


20

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

这意味着该if语句始终在else分支中。

为了说明这一点(这不正是发生的事情在你的情况,但它表明,如果GNU会发生什么grep无法写入它的输出):

$ echo 'hello' | grep hello >&- 2>&-
$ echo $?
2

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

这是GNU特有的grepgrep在BSD系统上的行为将有所不同:

$ echo 'hello' | grep hello >&- 2>&-    # using BSD grep here
$ echo $?
0

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

简而言之:

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

您也可以ping直接使用测试,从而消除对中间文件之一的需要(并且摆脱实际上只包含日期戳的其他中间文件):

#!/bin/sh

exec >/dev/null 2>&1

while true; do
    if ! ping -q -c 1 -W 1 myserver.net; then
        date | mutt -s "Server Down!" myemail@address.com
        break
    fi

    sleep 10
done

在上述脚本的两种变体中,我都选择在无法到达主机时退出循环,以尽量减少发送的电子邮件数量。如果希望服务器最终重新启动,则可以break用例如sleep 10m或代替。

我还略微调整了与一起使用的选项,ping因为与-i 1并没有多大意义-c 1

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

#!/bin/sh

exec >/dev/null 2>&1

while ping -q -c 1 -W 1 myserver.net; do
    sleep 10
done

date | mutt -s "Server Down!" myemail@address.com

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

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

使用>&-会关闭fd(例如,关闭文件描述符1),而关闭SSH连接会产生不同的效果(文件描述符仍然存在,但未连接到另一端。)仍然存在,那就是如果GNU grep尝试写入输出并且失败,则退出非零值。是的,最好的解决方案是直接检查ping的退出状态。
filbranden

4
通过exec </dev/null >/dev/null 2>&1在开头附近添加所有内容,将整个脚本重定向到/ dev / null /从/ dev / null重定向,可能更安全。这样,例如ping,如果决定写一些东西给stderr,那不会造成问题。
戈登·戴维森

@GordonDavisson我真的没有看到从/dev/null这里拉stdin的理由,但是我整理了输出。谢谢你的建议。
库萨兰达
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.