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)
这里我们grep为echo产生的字符串,但我们关闭了两个输出流,grep以便它不能在任何地方写入。如您所见,GNU 的退出状态grep是 2 而不是 0。
这是 GNU 特有的grep,grep在 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)