嘗試編寫一個持續遠端測試伺服器的 shell 腳本,但是當我註銷時它一直落在 else 語句中
在這裡嘗試編寫一個 shell 腳本來持續測試我的伺服器並在它出現故障時給我發電子郵件。
問題是,當我從 ssh 連接中註銷時,儘管
&
在命令結束時使用 like執行它,但./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
當 GNU
grep
嘗試寫入其結果時,它將以非零退出狀態失敗,因為它無處可寫輸出,因為 SSH 連接已消失。這意味著該
if
語句始終採用else
分支。為了說明這一點(這並不完全是您的情況,但它顯示瞭如果 GNU
grep
無法寫入其輸出會發生什麼):$ echo 'hello' | grep hello >&- 2>&- $ echo $? 2
在這裡,我們
grep
為產生的字元串echo
,但我們關閉了兩個輸出流,grep
以便它不能在任何地方寫入。如您所見,GNU 的退出狀態grep
是 2 而不是 0。這是 GNU 特有的
grep
,grep
在 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
eg或其他內容。sleep 10m
我還稍微調整了與
ping
as一起使用的選項,-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 )