Skip to main content

Bash script — проверка программы на запущенность и ее запуск

В общем, мне нужно было как-то примитивно проверить запущена ли программа, а если нет, то запустить её. Да, есть программы для мониторинга всего этого дела (например, mon), но ставить их из-за одной программы не хотелось, поэтому написал небольшой скрипт.

Сам скрипт:

#!/bin/bash
	ret=$(ps aux | grep [h]top | wc -l)
	if [ "$ret" -eq 0 ]
then {
	echo "Running Htop" #output text
        sleep 1  #delay
	htop #command for run program
	exit 1
}
else 
{
	echo "EXIT. Htop already running!"
	exit 1
}
fi;

Для начала смотрим запущена программа или нет:

ps aux | grep [h]top | wc -l

ps aux выводит запущенные процессы.
grep [h]top выводит результаты с htop, при этом если первую букву процесса взять в квадратные скобки, то ‘grep htop’ будет исключаться из списка.
wc -l подсчитывает количество строк (запущенных процессов).
Выглядит это так:

total@total-MS-7638:~$ ps aux 
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1  86904  4460 ?        Ss   16:04   0:00 /sbin/init
root         2  0.0  0.0      0     0 ?        S    16:04   0:00 [kthreadd]
root         3  0.0  0.0      0     0 ?        S    16:04   0:00 [ksoftirqd/0]
root         5  0.0  0.0      0     0 ?        S<   16:04   0:00 [kworker/0:0H]
root         6  0.0  0.0      0     0 ?        S    16:04   0:00 [kworker/u:0]
root         7  0.0  0.0      0     0 ?        S<   16:04   0:00 [kworker/u:0H]
root         8  0.0  0.0      0     0 ?        S    16:04   0:00 [migration/0]
root         9  0.0  0.0      0     0 ?        S    16:04   0:00 [rcu_bh]
syslog    1031  0.0  0.0 241120  1824 ?        Sl   16:04   0:00 rsyslogd -c5
root      1045  0.0  0.0  83408  3280 ?        Ss   16:04   0:00 /usr/sbin/modem-manager
root      1047  0.0  0.0  19240  1792 ?        Ss   16:04   0:00 /usr/sbin/bluetoothd
root      1076  0.0  0.0      0     0 ?        S<   16:04   0:00 [krfcommd]
root      1149  0.0  0.2 179000  9384 ?        Ss   16:04   0:00 /usr/sbin/cupsd -F
root      1163  0.0  0.1 246044  5868 ?        Ssl  16:04   0:00 NetworkManager
root      1168  0.0  0.1 250220  6872 ?        Sl   16:04   0:00 /usr/lib/policykit-1/polkitd --no-debug
root      1170  0.0  0.0  10720   916 tty4     Ss+  16:04   0:00 /sbin/getty -8 38400 tty4
root      1176  0.0  0.0  10720   920 tty5     Ss+  16:04   0:00 /sbin/getty -8 38400 tty5
root      1182  0.0  0.0  10720   908 tty2     Ss+  16:04   0:00 /sbin/getty -8 38400 tty2
root      1184  0.0  0.0  10720   916 tty3     Ss+  16:04   0:00 /sbin/getty -8 38400 tty3
root      1186  0.0  0.0  10720   916 tty6     Ss+  16:04   0:00 /sbin/getty -8 38400 tty6
root      1189  0.0  0.1  47312  4404 ?        Ssl  16:04   0:01 /opt/teamviewer8/tv_bin/teamviewerd -f
root      1214  0.0  0.0   4508   828 ?        Ss   16:04   0:00 acpid -c /etc/acpi/events -s /var/run/acpid.socket
daemon    1222  0.0  0.0  12792   136 ?        Ss   16:04   0:00 atd
root      1224  0.0  0.0  14992   980 ?        Ss   16:04   0:00 cron
root      1225  0.0  0.0  19148   728 ?        Ss   16:04   0:00 /usr/sbin/irqbalance
whoopsie  1234  0.0  0.1 282716  5044 ?        Ssl  16:04   0:00 whoopsie
openldap  1237  0.0  0.1 375504  6300 ?        Ssl  16:04   0:00 /usr/sbin/slapd -h ldap:/// ldapi:/// -g openldap -u openldap -F
colord    1266  0.0  0.1 210224  5444 ?        Sl   16:04   0:00 /usr/lib/colord/colord
root      1267  0.0  0.0  11876   840 ?        Sl   16:04   0:00 /usr/sbin/pcscd
root      1283  0.0  0.0 113448  1512 ?        Ss   16:04   0:00 /usr/sbin/sensord -f daemon
root      1296  0.0  0.0 124300  1948 ?        S    16:04   0:00 smbd -F
root      1311  0.0  0.0      0     0 ?        S<   16:04   0:00 [iprt]
root      1356  0.0  0.0 269148  3328 ?        Ssl  16:04   0:00 lightdm
root      1378  4.2  1.5 194792 60556 tty7     Ss+  16:04   9:01 /usr/bin/X :0 -core -auth /var/run/lightdm/root/:0 -nolisten tcp
total     3893  1.8  0.0  20752  2120 pts/1    S+   19:35   0:00 htop
total     3897  1.5  0.0  17496  3628 pts/2    Ss   19:35   0:00 bash
total     3945  0.0  0.0  13352  1256 pts/2    R+   19:35   0:00 ps aux
total@total-MS-7638:~$ ps aux | grep htop
total     3893  1.8  0.0  20752  2120 pts/1    S+   19:35   0:00 htop
total     3947  0.0  0.0  10684   952 pts/2    S+   19:35   0:00 grep --color=auto htop
total@total-MS-7638:~$ ps aux | grep [h]top
total     3893  1.8  0.0  20752  2120 pts/1    S+   19:35   0:00 htop
total@total-MS-7638:~$ ps aux | grep [h]top | wc -l
1
total@total-MS-7638:~$ ps aux | grep htop | wc -l
2
total@total-MS-7638:~$

После этого нужно написать условие проверки и запуска программы.
if [ "$ret" -eq 0 ] - если (if) значение переменной (ключ -eq означает равно) равно 0, то (then):
echo "Running Htop" - выводим текст: "Запускается Htop";
sleep 1 - ставим задержку при запуске в 1 секунду;
htop - запускаем программу Htop;
exit 1 - выходим из скрипта;
Иначе (else):
echo "EXIT. Htop already running!" - выводим текст: "Htop уже запущен!"
exit 1 - выходим из скрипта.
Конструкция "Если...то...иначе..." обязательно заканчивается fi;

Писать на Bash несложно, а также весьма увлекательно, в прочем, как и все в программировании. Так что попробуйте сами что-нибудь написать, у вас обязательно получится. Тем более, что по bash полно всякой документации, в том числе и на русском языке.

32 комментария к записи “Bash script — проверка программы на запущенность и ее запуск

  1. if [ "$ret" -eq 1 ] вот так работает с нулем всегда считает запущенным так как сама команда греп создает процесс и таким именем

    1. В пояснении к скрипту написано, как исключается из списка процессов сам grep.

  2. Походу ничего не выводит, скобки не воспринимает. Это урезанная pxe сборка для загрузки по nfs. А вот на основном серве с полноценной инсталяшкой все работает для интересу проверил.

    1. Если htop не запущен, команда и не должна ничего выводить. Скобки служат для исключения grep из вывода.
      Скорее всего, grep у Вас работает как раз верно, не смотря на сборку.

  3. Чё-то как-то сложновато у вас всё. Вот как я сделал бы:

    if [ -z "$(ps -C top --no-headers)" ] ; then top; fi

    Проверено на труъ убунте в bash и sh.

    А ps aux | grep [t]op выдаёт лично у меня нечто со словами org.freedesktop.

    Это, конечно, top, а не htop… Но зачем такое писать? Какие-то квадратные скобки… То ли выпендрёж, то ли костыли… Тем более с aux зачем-то… Зачем? Почему не -a, не -d, а именно aux? Не понимаю…

    Мало ли что там у человека запущено с таким сочетанием букв в путях, именах или параметрах… Вы бы ещё «e» в опции добавили для пущего веселья.

    1. Спасибо за полезный комментарий!
      Однако, справедливости ради замечу, что когда ты админишь сервера, то посмотреть вывод ps намного проще и быстрее, чем городить конструкции из if-условий 🙂 В скрипте, согласен, так выглядит элегантнее.

    2. До debian 10.5 работало отлично. На debian 10.5 такая конструкция у меня сломалась, в итоге нагенерировалось максимальное число (4915) процессов cron и все cron-скрипты встали с ошибкой «(CRON) error (can’t fork)» в syslog.

      1. В 10.6 также не работает, поэтому я просто написал юнит для systemd для своего python-скрипта, чтобы автоматом перезапускался, если вдруг упадет.

  4. Чтобы не считать вывод самой grep можно сделать так — ps ax | grep -v grep | grep ‘имя’

  5. Привет из 2к20, немного отредачил скрипт, мне кажется более правильна такая конструкция. Привет работы сквида.

    #!/bin/bash
    	ret=$(systemctl is-active squid)
    	if [[ "$ret" != "active" ]] #Конструкция [[ ]] более универсальна, по сравнению с [ ], Внутри этой конструкции не производится никакой дополнительной интерпретации имен файлов и не производится разбиение аргументов на отдельные слова, но допускается подстановка параметров и команд
    then 
    {
    	service squid start
    	exit 1
    }
    else 
    {
    	echo "EXIT. Squid already running!"
    	exit 1
    }
    fi;
    1. 1) Вы проверяете сервис, а не процесс. Не каждый процесс — это сервис.
      2) Будет работать для systemd, но не для SysVinit.

  6. Ребятки, идея хорошая конечно, но есть иной способ -> в /etc/crontab добавить строку

    */1 10-18 * * 1-5 zerg ps -e| grep eog || env DISPLAY=:0 eog -s /ARH/RIP/01.jpg

    описание строки ->
    Ежеминутно, с 10 до 18, с Пн по Пт, от имени zerg, проверять из запущенных процессов наличие запуска eog и если он не найден то запустить на дисплее :0 программу eog в полноэкранном режиме, именно определённый файл /ARH/RIP/01.jpg .

      1. название какое? «проверка программы на запущенность и ее запуск»
        программу проверит на запущенность крон, и если не запущена (рухнула по какой-то причине) то стартанет заново.
        в моём примере представлен запуск (на случай падения) трансляции картинок в слайдшоу на рекламном мониторе. по такой же аналогии можно запускать или выключать процессы на своё усмотрение и не ломать голову с громоздкими скриптами .
        вспомни что это и поймёшь как применить->
        &&
        ;
        ||

        1. О, теперь хоть цель скрипта стала ясна. Из первого комментария вообще не очевидно, для каких целей предложено использовать крон и запуск eog.

        2. Привет, а подскажи, как сделать, чтобы приходили уведомления на почту, если вдруг выяснилось,что службу приходилось перезапустить?

          1. Например,

            if [ -z "$(ps -C squid --no-headers)" ] ; then (printf "Squid died and has been restarted on $HOSTNAME\nCheck it please." | /bin/mail -s "Critical: squid died on $HOSTNAME" -r $HOSTNAME@site.ru monitor@site.ru && /etc/init.d/squid restart) ; fi
    1. Здравствуйте. Как прописать все тоже самое, только не для запуска дисплея, а для запуска процесса?

  7. На что только не идут люди лишь бы не использовать pidof.

    #!/bin/sh
    APP=appname_here
    [ "$(pidof $APP)" ] ||$APP
        1. а никак, это просто один из способов. какой тебе удобен тем и пользуйся.

        2. cron позволяет выполнять проверки минимум раз в минуту. Можно еще заморочиться с incrontab, но проще через sleep в цикле запустить.

          1. В отличии от Cron, скрипт запускает процесс один раз — только при старте системы? То есть если во время работы процесс упадет, то скрипт его не запустит?

          2. У меня получилось реализовать данную задачу без скрипта, как парень выше показал с дисплеем.
            Я добавил в /etc/crontab следующую строку:
            */1 * * * * root ps -A | grep xxx > /dev/null || /etc/init.d/xxx start
            где xxx — имя программы
            Так же после grep xxx я прописал > /dev/null, чтобы каждую минуту после проверки процесса xxx на запущенность не создавалось новое письмо в файле /var/spool/mail/root и не выдавалось об этом сообщение в терминале.
            Принцип работы команды я понял, но на всякий случай хотелось бы у вас уточнить какое условие выполняет данный символ ||, так как я в этом вообще не разбираюсь.
            Как я понимаю, он выполняет следующее условие — если процесс xxx не найден, то выполнить команду /etc/init.d/xxx start, правильно я понимаю? И правильно ли я сделал остальное? Пока все работает, но спрашиваю ваше мнение на случай возможных проблем из-за возможной ошибки.

          3. Да, || — логическое «или», то есть ищем процесс, «иначе» (если не нашли) запускаем его.
            a && b — если выполнилось a, нужно выполнить b
            a || b — если a не выполнилось, выполнить b

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *