Попытка написать сценарий оболочки, который продолжает тестировать сервер удаленно, но при выходе из системы он продолжает падать в операторе else

Вы пытаетесь определить концепцию, которой просто не существует. Вы не найдете общего понятия «имя программы» или «имени приложения», которое выходит за рамки того, что вы можете найти в качестве имени исполняемого файла.

Имя исходного файла и , как правило, не сохраняются в исполняемом файле. Для скрипта «основным» исходным файлом является имя исполняемого файла, но скрипт также использует код из множества других мест (по крайней мере интерпретатора ). Для скомпилированной программы информация недоступна во время выполнения, если только что-то специфичное для компилятора или цепочки сборки не помещает ее туда, а в большинстве случаев этого не происходит.

Просмотр /proc/$pid/exeдает путь к исполняемому файлу. Все процессы имеют исполняемый файл¹. Исполняемый файл мог быть переименован или удален с момента запуска процесса. Это единственное универсальное понятие «имя программы».

Первый элемент /proc/$pid/cmdline— это аргумент 0, передаваемый при вызове процесса. Это имя выбирается вызывающей стороной процесса. Если вызывающая сторона не ушла со своего пути, обычно это базовое имя исполняемого файла, с частью каталога или без нее, в зависимости от того, была ли программа вызвана через поиск в PATH. Процесс может перезаписать эту часть, но некоторые программы делают это в основном (, несколько демонов делают это, чтобы отразить свой статус таким образом, который можно легко увидеть с помощьюps).

Linux также хранит имя процесса, о котором сообщает ps -o comm. Он доступен через /proc/$pid/status. Это исходное базовое имя исполняемого файла, усеченное до 16 байт.

¹ В /procесть записи, ссылка exeкоторых не читается. Это потоки ядра или зомби, а не процессы. Для всех процессов ссылка доступна для чтения (с надлежащим разрешением ), хотя она может не указывать на существующий файл, если исполняемый файл был удален.

9
09.10.2019, 22:55
1 ответ

Когда 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

Поскольку задание cron выполняется каждую минуту, (будет продолжать отправлять электронные письма каждую минуту, если сервер по-прежнему не работает):

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

Теги

Похожие вопросы