Почему я получаю другой статус выхода для PS | grep в скрипте?

11

Я бегу ниже сценария:

#!/bin/bash

ps ax  | grep -q [v]arnish
if [ $? -eq 0 ];then
        echo varnish is running...
        exit 0
else
        echo "Critical : varnish is not running "
        exit 2
fi

Выход похож на ::

[root@server ~]# sh -x check_varnish_pro.sh
+ ps ax
+ grep -q '[v]arnish'
+ '[' 0 -eq 0 ']'
+ echo varnish is running...
varnish is running...
+ exit 0

Когда я запускаю то же самое в командной строке, я получаю статус выхода как 1:

[root@server ~]# ps ax  | grep -q [v]arnish; echo $?
1

Дело в том, что лак не установлен на сервере. Этот скрипт отлично работает на сервере, где установлен лак.

Почему разные состояния выхода при запуске с использованием скрипта и командной строки? Как улучшить этот скрипт?

Prado
источник
Используйте реальную систему контроля процессов, а не такого рода хакерские атаки. Ваша операционная система почти наверняка будет иметь встроенный способ гарантировать, что ваши демоны, которые вы хотите сохранить, автоматически перезапускаются при сбое, будь то upstart, daemontools, systemd, launchd или одна из многих, многих других альтернатив. Все они будут более надежными и способными, чем этот вид ручного взлома.
Чарльз Даффи

Ответы:

10

Когда вы запускаете скрипт с именем check_varnish_pro.shтеста

ps ax  | grep -q [v]arnish

успешно, потому что есть скрипт с именем check_varnish_pro .

AlexP
источник
14

В общем, плохая идея попробовать простой подход psи grepпопытаться определить, запущен ли данный процесс.

Вам было бы гораздо лучше использовать pgrepдля этого:

if pgrep "varnish" >/dev/null; then
  echo "Varnish in running"
else
  echo "Varnish is not running"
fi

Смотрите руководство для pgrep. В некоторых системах (возможно, не в Linux) вы получаете -qфлаг, соответствующий тому же флагу, для grepкоторого избавляется от необходимости перенаправления /dev/null. Также есть -fфлаг, который выполняет сопоставление в полной командной строке, а не только в имени процесса. Можно также ограничить соответствие процессами, принадлежащими конкретному пользователю, использующему -u.

Установка pgrepтакже дает вам доступ к pkillкоторому позволяет сигнализировать о процессах на основе их имен.

Кроме того, если это демон службы , и если ваша система Unix имеет способ запрашивать у него информацию (например, работает ли она или нет), тогда это правильный способ проверки.

В Linux у вас есть systemctl( systemctl is-active --quiet varnishвернет 0, если он работает, 3 в противном случае), в OpenBSD у вас есть rcctlи т. Д.


Теперь к вашему сценарию:

В вашем скрипте вы анализируете вывод из ps ax. Этот вывод будет содержать имя самого скрипта check_varnish_pro.sh, который, очевидно, содержит строку varnish. Это дает вам ложный положительный результат. Вы бы заметили это, если бы тестировали его без -qфлага grep.

#!/bin/bash
ps ax | grep '[v]arnish'

Запуск это:

$ ./check_varnish_pro.sh
31004 p1  SN+     0:00.04 /bin/bash ./check_varnish_pro.sh

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

Видеть:

bash-4.4$ set -x
bash-4.4$ ps ax | grep [v]arnish
+ ps ax
+ grep '[v]arnish'
bash-4.4$ touch varnish
+ touch varnish
bash-4.4$ ps ax | grep [v]arnish
+ ps ax
+ grep varnish
91829 p2  SN+p    0:00.02 grep varnish

Наличие файла varnishприведет к тому, что оболочка заменит [v]arnishимя файла, varnishи вы получите удар по шаблону в таблице процессов ( grepпроцесс).

Кусалананда
источник
4
потому что все это файл "в земле Linux".
Зи
@ z_- Не совсем уверен, как он подключен, но это справедливо даже для не-Linux Unices.
Кусалананда
4
Не только процесс grep; имя сценария check_varnish_pro.shтакже является фактором.
TNW
@TNW Сначала я этого не заметил, но ты прав. Я добавлю это в.
Кусалананда
3

@AlexP очень кратко объясняет, что происходит на самом деле, но идея @ Kusalananda использовать pgrep/ pkillдля критического процесса настоятельно не рекомендуется . Лучшие решения включают в себя:

  • Спрашивая сервис , работает ли он. systemctl status varnishdследует позаботиться об этом на современной установке * nix.
  • Если по каким-то непредвиденным обстоятельствам у вас нет доступной службы, вы можете просто изменить сценарий запуска, чтобы сообщить о проблеме, как только процесс завершится:

    varnish || true
    some_command_to_send_an_alert_that_the_service_has_died
  • Либо измените сценарий, запускающий службу для записи PID, а затем периодически проверяйте состояние с помощью kill -0 "$pid".
l0b0
источник
Я согласен, я только обращался к аспектам сценариев оболочки проблемы. Обратите внимание, что systemctlэто доступно почти только в Linux (AFAIK), и не во всех современных Unix-подобных системах.
Кусалананда
Оригинальный вопрос имел тег «linux»; Я не уверен, почему это было удалено @muru.
10
Спасибо, l0b0. У меня было два вопроса «Почему» и «Как улучшить». @ Ответ AlexP решил мой первый вопрос, а ваш ответ - лучшее решение для второго вопроса. Но Кусалананда объясняет связанные с этим вещи, которые, я думаю, будут полезны для людей, у которых есть подобные проблемы. Так что я сейчас в замешательстве, чтобы принять ответ.
Прадо
@prado Какое бы решение ни
10