Намагаюся написати скрипт оболонки, який продовжує тестувати сервер віддалено, але він продовжує потрапляти в оператор else, коли я виходжу


9

Спробую тут написати скрипт оболонки, який продовжує тестувати мій сервер і надсилати мені електронну пошту, коли він не працює.

Проблема полягає в тому, що коли я виходжу з з'єднання ssh, незважаючи на запуск його &в кінці команди, наприклад ./stest01.sh &, він автоматично потрапляє в інше і продовжує безперервно надсилати мені повідомлення, поки я знову не ввійду і не вб'ю його.

#!/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
Я не фахівець з басу, але що робить двокрапка :? Мені було б сенсом, що це крапка з комою ;...
Ned64,

3
@ Ned64 :Нічого не робить. Це те, що воно покликане робити. Тут замість того, щоб перевертати тест, вони використовують його для попереднього відключення else.
Kusalananda

@Kusalananda Добре, дякую. Думав, що це може бути помилка, яка може пояснити проблему.
Ned64

1
Мене також бентежить, чому б спробувати залишити скрипт оболонки після запуску. Чи не були б кращі або кращі таймери для цього?
Кліфф Армстронг

Відповіді:


20

Коли 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наприклад, на 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

Як робота з хроном, що працює щохвилини (продовжуватиме надсилати електронні листи щохвилини, якщо сервер продовжує працювати):

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

Використання >&-закриє fd (як у, дескриптор файлу 1 закритий), а закриття з'єднання SSH матиме інший ефект (дескриптор файлу все ще буде навколо, але не пов'язаний ні з чим з іншого боку.) Я думаю, що справа все ще стоїть, що полягає в тому, що grep GNU виходить з нуля, якщо він намагається записати вихід, і це не вдалося. Так, найкраще рішення - це просто перевірити стан виходу ping безпосередньо.
filbranden

4
Можливо, безпечніше буде просто перенаправити все на / з / dev / null для всього сценарію, додавши exec </dev/null >/dev/null 2>&1біля початку. Таким чином, якщо напр. pingВирішить написати щось для більш жорсткого, це не спричинить проблем.
Гордон Девіссон

@GordonDavisson Я насправді не бачу причини витягувати stdin /dev/nullзвідси, але я розібрав вихід. Дякую за пропозицію.
Kusalananda
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.