Как определить, запущен процесс или нет, и использовать его для создания условного сценария оболочки?

108

Как я могу определить, запущен процесс или нет, а затем выполнить сценарий bash для выполнения каких-либо действий на основе этого условия?

Например:

  • если процесс abcзапущен, сделайте это

  • если это не работает, сделайте это.

Nirmik
источник
1
Считайте важным отметить, что ни одно из приведенных ниже решений не учитывает состояние процесса. Комментарий по одному из моих вопросов привел меня сюда, но ответ на него дал мне представление о различных состояниях программы, например о zombieпроцессе (не то, что я бы назвал «запущенным» процессом). Полный список STATзначений столбцов в выходных данных psприведен здесь для тех, кто склонен написать ответ, который учитывает это, или отредактировать свой собственный.
user66001
Связанные обсуждения: unix.stackexchange.com/questions/74185/...
Blong
лучший способ проверить процесс существует: stackoverflow.com/questions/3043978/…
Тревор Бойд Смит

Ответы:

166

Сценарий bash, выполняющий что-то подобное, будет выглядеть примерно так:

#!/bin/bash

# Check if gedit is running
# -x flag only match processes whose name (or command line if -f is
# specified) exactly match the pattern. 

if pgrep -x "gedit" > /dev/null
then
    echo "Running"
else
    echo "Stopped"
fi

Этот скрипт просто проверяет, запущена ли программа "gedit".

Или вы можете только проверить, работает ли программа следующим образом:

if ! pgrep -x "gedit" > /dev/null
then
    echo "Stopped"
fi
Джон Врбанак
источник
@DreadPirateShawn Можете ли вы сказать мне, почему использовать / dev / null, а не просто 0? Использование числа делает код более читабельным, по крайней мере, для нуба (такого как я). Нет перенаправления, нет ничего
Сильвиу
2
@ Сильвиу, а? Поиск в Google /dev/null: "/ dev / null перенаправляет стандартный вывод команды на нулевое устройство, которое является специальным устройством, которое отбрасывает записанную в него информацию" ... использование 0перенаправит вывод команды в файл с именем 0. В этом случае я бы посоветовал почувствовать себя более комфортно > /dev/null- вы увидите это повсюду, так как это стандартный / правильный способ отменить вывод.
DreadPirateShawn
Спасибо, я использовал это для милого маленького скрипта, который проверяет, запущена ли программа перед ее выполнением. (хотя мне пришлось немного его расширить, поскольку исполняемый файл google chrome не имеет того же имени, что и команда run, имя exec просто chrome.)
Cestarian
3
Пожалуйста, добавьте -xпараметр, чтобы pgrepон искал точное приложение, иначе он получит неверное значение, если найдет ту же строку в имени другого приложения. Я просто потратил 1 час, чтобы выяснить это.
Танос Апостолоу
1
Чтобы проверить, не запущена ли программа, используйте! pgrep
Мохаммед Нурельдин
36

Любое решение, которое использует что-то вроде ps aux | grep abcили pgrep abcимеет недостатки.

Почему?

Поскольку вы не проверяете, запущен ли конкретный процесс, вы проверяете, запущены ли какие-либо процессы, которые совпадают abc. Любой пользователь может легко создать и запустить исполняемый файл с именем abc(или содержащий abcего в своем имени или аргументах), что приведет к ложному срабатыванию вашего теста. Есть различные варианты , которые можно применить к ps, grepи pgrepсузить область поиска, но вы все равно не получите надежный тест.

Итак, как мне надежно протестировать определенный процесс?

Это зависит от того, для чего вам нужен тест.

Я хочу убедиться, что служба abc запущена, и если нет, запустите ее

Для этого и нужны init и upstart. Они запустят службу и гарантируют, что ее pid будет сохранен в pidfile. Попробуйте снова запустить службу (через init или upstart), и она проверит pid-файл и либо запустит его, если его там нет, либо прервет работу, если он уже запущен. Это все еще не на 100% надежно, но это так близко, как вы получите.

Посмотрите, как я могу проверить, работает ли мой игровой сервер ... для других решений.

ABC это мой сценарий. Мне нужно убедиться, что запущен только один экземпляр моего скрипта.

В этом случае используйте файл блокировки или файл блокировки. Например

#!/usr/bin/env bash

if ! mkdir /tmp/abc.lock; then
    printf "Failed to acquire lock.\n" >&2
    exit 1
fi
trap 'rm -rf /tmp/abc.lock' EXIT  # remove the lockdir on exit

# rest of script ...

См. Bash FAQ 45 для других способов блокировки.

geirha
источник
3
Хотя это технически верно, я никогда не сталкивался с такой проблемой в реальной жизни. Большинство программ не меняют свои имена так, как это нарушает сценарии. Таким образом, для простых сценариев что-то вроде pgrepили psвполне адекватно, и ваш подход кажется излишним. Если вы пишете сценарий для публичного распространения, вы должны писать его максимально безопасным способом.
Скотт Северанс
2
@ScottSeverance Программы, меняющие имена, не проблема; это потребует вмешательства независимо. Это другие пользователи, работающие с той же самой программой, или другие программы с похожими именами, которые внезапно приведут к тому, что скрипт получит ложные срабатывания и, таким образом, поступит неправильно. Я просто предпочитаю «работает», а не «в основном работает».
гейра
2
Я оговорился. Но многие из нас используют однопользовательские системы. И в многопользовательской ситуации легко также использовать grep для имени пользователя.
Скотт Северанс
1
Что делать, если ваш скрипт не работает во время выполнения и умирает до разблокировки файла?
jp093121
2
@ jp093121 Ловушка EXIT срабатывает при выходе из сценария. Независимо от того, выходит ли он из-за достижения конца сценария, команды выхода или получает сигнал (который может быть обработан), rmкоманда запускается. Так что, пока он заканчивается после того, как ловушка установлена, замок должен исчезнуть.
гейра
18

Это то, что я использую:

#!/bin/bash

#check if abc is running
if pgrep abc >/dev/null 2>&1
  then
     # abc is running
  else
     # abc is not running
fi

Говоря простым языком: если 'pgrep' возвращает 0, процесс выполняется, в противном случае это не так.


Связанное чтение:

Bash Scripting :: Сравнение строк

Руководства по Ubuntu pgrep

Zuul
источник
спасибо! я попробовал это тоже, и это прекрасно работает :)
Nirmik
pgrepимеет ту же «особенность» ограничения в 15 символов, о которой упоминалось ранее, поэтому, например pgrep gnome-power-manager, также потерпит неудачу
Торсен
1
Убедитесь, что вы используете -xопцию pgrep : «Только сопоставлять процессы, чье имя (или командная строка, если указан -f) точно соответствует шаблону».
Аластер Ирвин
5

У меня обычно есть pidof -x $(basename $0)сценарии, чтобы проверить, запущен ли он.

Роммель Сид
источник
2

Следуя идее @ rommel-cid, вы можете использовать pidofс || (||) для запуска команды, если процесс не существует, и && для запуска чего-либо, если процесс существует, создавая быстрое условное условие if / then / else. Например, вот один с запущенным процессом (мой браузер Chrome, имя процесса которого «chrome») и один тест для процесса, который не существует. Я подавил стандартный вывод, используя 1> / dev / null, чтобы он не печатался:

$ (pidof chrome 1>/dev/null && echo "its running? ok, so am i then" ) || echo "it's not running? ok i'll run instea\
d"
its running? ok, so am i then
$ (pidof nosuchprocess 1>/dev/null && echo "its running? ok, so am i then" ) || echo "it's not running? ok i'll run\
 instead"
it's not running? ok i'll run instead
$
yuvilio
источник
1

Ни одно из «простых» решений не сработало для меня, потому что бинарный файл, который мне нужно проверить, не установлен в масштабе всей системы, поэтому я должен проверить с помощью пути, что, в свою очередь, требует использования ps -ef | grepподхода:

app="$_sdir/Logic 1.2.18 (64-bit)/Logic"

app_pid=`ps -ef | grep "$app" | awk '{print $2}'`

if `ps -p $app_pid > /dev/null`; then
    echo "An instance of logic analyzer is appear to be running."
    echo "Not starting another instance."
    exit 5
else
    nohup "$app" &> /dev/null &
fi
ceremcem
источник
0

Первое, что пришло мне в голову по вашей проблеме:
ps aux | grep -i abcпокажет детали процесса, если он запущен. Вы можете сопоставить количество строк или время, в течение которого он работает, и сравнить его с нулем или любой другой манипуляцией. Когда вы запустите указанную выше команду, она покажет вам по крайней мере одну строку вывода, т.е. подробную информацию о процессе, созданном командой thi grep. Так что позаботьтесь об этом.
Это должно быть простым взломом. Поместите его в скрипт bash и посмотрите, будет ли он полезным.

drake01
источник
0

Использование start-stop-daemon:

/sbin/start-stop-daemon --background --make-pidfile --pidfile /tmp/foo.pid -S --startas /usr/bin/program -- arg1 arg2

Работает как обычный пользователь.

Мартин Монперрус
источник
0

Я обнаружил, что принятый ответ @John Vrbanac не работает для меня, и что ответ @geirha не отвечает на исходный вопрос.

Решение Джона Врбанака не помогло проверить, запущен ли процесс PHP для меня или нет, я использую CentOS 7.

Ответ @ geirha только гарантирует, что экземпляр еще не запущен, прежде чем запускать другой. Это не был первоначальный вопрос, первоначальный вопрос состоял в том, чтобы проверить, запущен процесс или нет.

Вот что сработало для меня:

Скажем, у моего процесса была строка «Джейн» в имени процесса. Это найдет, работает он или нет. Это работает для скриптов BASH и PHP.

ps -aux | grep "[J]ane" > /dev/null 2>&1
if [[ "$?" == "0" ]]; then
    echo "It's running"
else
    echo "It's not running"
fi
Уэйн Уоркман
источник
1
Ах, ну, это сайт вопросов и ответов Ubuntu, поэтому неудивительно, что некоторые ответы здесь не работают с CentOS 7, поскольку Linux здесь не по теме. Другие версии Linux поддерживаются на unix.stackexchange.com
Elder Geek
хотя автор ответа использует CentOS, этот ответ по-прежнему действителен для Ubuntu.
Филипп-Зьян К Ли - Стокманн
0
## bash

## function to check if a process is alive and running:

_isRunning() {
    ps -o comm= -C "$1" 2>/dev/null | grep -x "$1" >/dev/null 2>&1
}

## example 1: checking if "gedit" is running

if _isRunning gedit; then
    echo "gedit is running"
else
    echo "gedit is not running"
fi

## example 2: start lxpanel if it is not there

if ! _isRunning lxpanel; then
    lxpanel &
fi

## or

_isRunning lxpanel || (lxpanel &)

Примечание : pgrep -x lxpanelили по- pidof lxpanelпрежнему сообщает, что lxpanelработает, даже если он не работает (зомби); поэтому, чтобы получить живой и работающий процесс, нам нужно использовать psиgrep

Бах Лиен
источник
-1

По состоянию на 23 сентября 2016 года pgrep, по-видимому, требует опцию «-x» для работы скрипта muru.

#!/bin/bash

if pgrep -x "conky" > /dev/null 2>&1
then
  echo "conky running already"
else
  echo "now starting conky"
  conky
fi
exit 0

Я попробовал и протестировал вышеуказанный скрипт на машине с Ubuntu 16.04.1. Наслаждайтесь!

dzmanto
источник
-1
#!/bin/bash
while [ true ]; do     # Endless loop.
  pid=`pgrep -x ${1}`  # Get a pid.
  if [ -z $pid ]; then # If there is none,
    ${1} &             # Start Param to background.
  else
    sleep 60           # Else wait.
  fi
done
user7449824
источник
1
Добро пожаловать в Спросите Ubuntu! Я рекомендую отредактировать этот ответ, чтобы расширить его конкретными сведениями о том, что это делает. (См. Также Как написать хороший ответ? Для общего совета о том, какие ответы считаются наиболее ценными в AskUbuntu.)
Дэвид Фёрстер
-3

isProcessRunning () {if [$ (pidof $ 1)> / dev / null]; затем retval = 'true'; иначе retval = 'ложь'; Fi; echo $ retval; }

isProcessRunning geany

правда

Dominic
источник