Mencoba untuk menulis skrip shell yang terus menguji server dari jarak jauh, tetapi tetap jatuh dalam pernyataan lain ketika saya logout

9

Mencoba di sini untuk menulis skrip shell yang terus menguji server saya dan mengirim email kepada saya ketika sudah down.

Masalahnya adalah ketika saya logout dari koneksi ssh, meskipun menjalankannya dengan &di akhir perintah, seperti ./stest01.sh &, secara otomatis jatuh ke yang lain dan terus mengirimi saya tanpa gangguan, sampai saya login lagi dan membunuhnya.

#!/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
Vasconcelos1914
sumber
1
Saya bukan ahli bash, tapi apa yang dilakukan usus besar :? Akan masuk akal bagi saya itu adalah titik koma ;...
Ned64
3
@ Ned64 Tidak :melakukan apa-apa. Inilah yang dirancang untuk dilakukan. Di sini, alih-alih membalik tes, mereka menggunakannya untuk melakukan no-op sebelumnya else.
Kusalananda
@ Kusalananda OK, terima kasih. Kupikir itu mungkin salah ketik yang bisa menjelaskan masalahnya.
Ned64
1
Saya juga bingung mengapa orang akan mencoba untuk membiarkan skrip shell berjalan setelah logout. Bukankah timer cron atau systemd menjadi pilihan yang lebih baik untuk ini?
Cliff Armstrong

Jawaban:

20

Ketika GNU grepmencoba untuk menulis hasilnya, ia akan gagal dengan status keluar yang tidak nol, karena ia tidak punya tempat untuk menulis output, karena koneksi SSH hilang.

Ini berarti bahwa ifpernyataan itu selalu mengambil elsecabang.

Untuk menggambarkan hal ini (ini bukan persis apa yang terjadi dalam kasus Anda, tapi itu menunjukkan apa yang terjadi jika GNU greptidak dapat menulis output):

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

Di sini kita grepmencari string yang echomenghasilkan, tetapi kita menutup kedua aliran keluaran grepagar tidak dapat menulis di mana pun. Seperti yang Anda lihat, status keluar dari GNU grepadalah 2 daripada 0.

Ini khusus untuk GNU grep, greppada sistem BSD tidak akan berlaku sama:

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

Untuk memperbaiki ini, pastikan skrip tidak menghasilkan output. Anda dapat melakukannya dengan exec >/dev/null 2>&1. Juga, kita harus menggunakan grepdengan -qopsi ini karena kita sama sekali tidak tertarik melihat output dari itu (ini umumnya juga akan mempercepat grepkarena tidak perlu menguraikan seluruh file, tetapi dalam hal ini membuat sangat sedikit perbedaan kecepatan karena file sangat kecil).

Pendeknya:

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

Anda juga dapat menggunakan tes pinglangsung, menghapus kebutuhan untuk salah satu file perantara (dan juga menyingkirkan file perantara lainnya yang benar-benar hanya berisi datestamp):

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

Dalam kedua variasi skrip di atas, saya memilih untuk keluar dari loop setelah gagal mencapai host, hanya untuk meminimalkan jumlah email yang dikirim. Anda bisa mengganti breakdengan eg sleep 10matau sesuatu jika Anda mengharapkan server akhirnya muncul lagi.

Saya juga sedikit mengubah opsi yang digunakan pingsebagai-i 1 tidak masuk akal -c 1.

Lebih pendek (kecuali jika Anda ingin terus mengirim email ketika tuan rumah tidak terjangkau):

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

Sebagai pekerjaan cron yang berjalan setiap menit (akan terus mengirim email setiap menit jika server terus turun):

* * * * * ping -q -c 1 -W 1 >/dev/null 2>&1 || ( date | mail -s "Server down" myemail@address.com )
Kusalananda
sumber
Menggunakan >&-akan menutup fd (seperti pada, file deskriptor 1 ditutup), sementara menutup koneksi SSH akan memiliki efek yang berbeda (deskriptor file akan tetap ada, tetapi tidak terhubung ke apa pun di sisi lain.) Saya pikir intinya masih berdiri, yaitu bahwa grep GNU keluar non-nol jika ia mencoba untuk menulis keluaran dan itu gagal. Ya, solusi terbaik hanya memeriksa status keluar ping secara langsung.
filbranden
4
Mungkin lebih aman untuk mengarahkan ulang semuanya ke / dari / dev / null untuk seluruh skrip dengan menambahkan exec </dev/null >/dev/null 2>&1mendekati awal. Dengan begitu jika misalnya pingmemutuskan untuk menulis sesuatu ke stderr itu tidak akan menimbulkan masalah.
Gordon Davisson
@ GordonDavisson Saya tidak benar-benar melihat alasan untuk menarik stdin dari /dev/nullsini, tapi saya bereskan hasilnya. Terima kasih untuk sarannya.
Kusalananda