Команда Linux / Unix, чтобы определить, запущен ли процесс?


99

Мне нужна независимая от платформы (Linux / Unix | OSX) команда shell / bash, которая определит, запущен ли конкретный процесс. например mysqld, httpd... Каков самый простой способ / команда сделать это?

Ответы:


170

Хотя pidofи pgrepявляются отличными инструментами для определения того, что работает, они, к сожалению, недоступны в некоторых операционных системах. Определенным отказоустойчивым было бы использование следующего:ps cax | grep command

Вывод в Gentoo Linux:

14484? S 0:00 apache2
14667? S 0:00 apache2
19620? Сл 0:00 apache2
21132? СС 0:04 apache2

Вывод в OS X:

42582 ?? Z 0: 00.00 (клиент)
46529 ?? Z 0: 00.00 (клиент)
46539 ?? Z 0: 00.00 (клиент)
46547 ?? Z 0: 00.00 (клиент)
46586 ?? Z 0: 00.00 (клиент)
46594 ?? Z 0: 00.00 (клиент)

И в Linux, и в OS X grep возвращает код выхода, поэтому легко проверить, был ли процесс найден или нет:

#!/bin/bash
ps cax | grep httpd > /dev/null
if [ $? -eq 0 ]; then
  echo "Process is running."
else
  echo "Process is not running."
fi

Кроме того, если вам нужен список PID, вы также можете легко найти его:

ps cax | grep httpd | grep -o '^ [] * [0-9] *'

Чей вывод одинаков в Linux и OS X:

3519 3521 3523 3524

Результатом следующего является пустая строка, что делает этот подход безопасным для неработающих процессов:

эхо ps cax | grep aasdfasdf | grep -o '^[ ]*[0-9]*'

Этот подход подходит для написания простого теста пустой строки, а затем даже для перебора обнаруженных PID.

#!/bin/bash
PROCESS=$1
PIDS=`ps cax | grep $PROCESS | grep -o '^[ ]*[0-9]*'`
if [ -z "$PIDS" ]; then
  echo "Process not running." 1>&2
  exit 1
else
  for PID in $PIDS; do
    echo $PID
  done
fi

Вы можете протестировать его, сохранив его в файл (с именем "running") с разрешениями на выполнение (chmod + x running) и выполнив его с параметром: ./running "httpd"

#!/bin/bash
ps cax | grep httpd
if [ $? -eq 0 ]; then
  echo "Process is running."
else
  echo "Process is not running."
fi

ПРЕДУПРЕЖДЕНИЕ!!!

Имейте в виду, что вы просто анализируете вывод, ps axчто означает, что, как видно из вывода Linux, это не просто сопоставление процессов, но и аргументы, переданные этой программе. Я настоятельно рекомендую быть как можно более конкретным при использовании этого метода (например ./running "mysql", также будет соответствовать процессам mysqld). Я настоятельно рекомендую использовать whichдля проверки полного пути, где это возможно.


Ссылки:

http://linux.about.com/od/commands/l/blcmdl1_ps.htm

http://linux.about.com/od/commands/l/blcmdl1_grep.htm


Процесс может быть запущен, но остановлен. Так что, если цель состоит в том, чтобы проверить, работают ли mysqld или httpd (отвечает), вы также должны проверить, остановлен он или нет.
oluc

2
Извините, но хотя ответ определенно верен с семантической точки зрения, я категорически против попыток найти процесс путем сопоставления с образцом в векторе arg процесса. Любой такой подход рано или поздно обречен на провал (вы фактически признаете это сами, говоря, что необходимы дополнительные проверки). Я добавил свою рекомендацию в отдельный ответ.
Питер 03

6
grepбудет также найти сам работает (например , ps cax | grep randomnameвсегда возвращает 0 , потому что grepнаходки grep randomname(надеюсь , это понятно ...) Одним из способов исправить это добавить квадратные скобки вокруг первой буквы имени процесса, например. ps cax | grep [r]andomname.
Кайл Г.

ps cax | rev | cut -f1 -d' ' | revбудет отображать только столбец имени для облегчения анализа.
Tyzoid

1
ps caxможет не выводить имя команды полностью. Например, он печатает «хром-браузер» вместо «хром-браузер».
Ярно

25

Вы ДОЛЖНЫ знать PID!

Поиск процесса путем попытки распознать какой-то образ на аргументах процесса (например, pgrep "mysqld") - это стратегия, которая рано или поздно обречена на провал. Что делать, если у вас работает два mysqld? Забудьте об этом подходе. Вы МОЖЕТЕ сделать это временно, и это МОЖЕТ работать в течение года или двух, но затем происходит что-то, о чем вы не думали.

Только идентификатор процесса (pid) действительно уникален.

Всегда сохраняйте pid, когда запускаете что-то в фоновом режиме. В Bash это можно сделать с помощью $!переменной Bash. Поступив так, вы избавите себя от ТАКИХ проблем.

Как определить, запущен ли процесс (по pid)

Итак, теперь возникает вопрос, как узнать, запущен ли pid.

Просто сделайте:

ps -o pid = -p <pid>

Это POSIX и, следовательно, переносимый. Он вернет сам pid, если процесс запущен, или ничего не вернет, если процесс не запущен. Строго говоря, команда вернет один столбец,pid но, поскольку мы дали ему пустой заголовок (материал, непосредственно предшествующий знаку равенства), и это единственный запрошенный столбец, команда ps вообще не будет использовать заголовок. Это то, что мы хотим, потому что это упрощает синтаксический анализ.

Это будет работать в Linux, BSD, Solaris и т. Д.

Другой способ - проверить значение выхода из приведенной выше psкоманды. Он должен быть равен нулю, если процесс запущен, и отличному от нуля, если нет. Спецификация POSIX говорит, что psдолжно выйти> 0, если произошла ошибка, но мне неясно, что составляет «ошибку». Поэтому я лично не использую эту стратегию, хотя уверен, что она также будет работать на всех платформах Unix / Linux.


1
За исключением того, что это не отвечает на вопрос, который должен определить, запущена ли служба. PID не будет известно , в таких случаях, поэтому этот ответ является действительным , только если вы делаете знать PID.
Шоссе Жизни

2
Неправильно. Весь мой смысл комментария состоит в том, чтобы сделать шаг назад и сказать, что если вы сначала окажетесь в ситуации, когда вам нужно сделать какую-то форму, grep <sometext>чтобы найти данный процесс, то вы сделали что-то не так, когда начали процесс, ИМХО. Я исхожу из вопроса ОП, что он действительно контролирует запуск процесса.
peterh

2
Более правильным «термином» для вопроса OP должно было быть «кроссплатформенная команда для определения, запущена ли служба», это не та же система, которая выполняет проверку, а внешняя система, поэтому PID просто не будет известно вообще.
Шоссе Жизни

2
Это не надежно. Интересующий вас процесс мог умереть после того, как система проработала достаточно долго, чтобы идентификаторы PID можно было обернуть, и затем другому процессу мог быть назначен тот же PID, который вы проверяете. stackoverflow.com/questions/11323410/linux-pid-recycling
глина

1
@ оклейка. Честная оценка. Однако метод PID по-прежнему лучше, чем сопоставление с образцом в аргументах процесса, поскольку конфликт PID гораздо более маловероятен, чем, скажем, случайный запуск двух экземпляров одной и той же службы. Всего два цента. :-)
peterh

15

В большинстве дистрибутивов Linux вы можете использовать pidof (8).

Он напечатает идентификаторы всех запущенных экземпляров указанных процессов или ничего, если нет запущенных экземпляров.

Например, в моей системе (у меня четыре экземпляра bashи один экземпляр remminaзапущен):

$ pidof bash remmina
6148 6147 6144 5603 21598

В других Unices pgrepили в комбинации psи grepдостигнет того же самого, как справедливо указывали другие.


+1 pidof httpdотлично работает на Red Hat 5. Но на моем Red Hat 4 pidofнет :-(
olibre 02

Действительно, эта команда менее распространена, чем я думал, я отредактировал свой ответ, чтобы сделать это более понятным.
Frédéric Hamidi

Действительно хороший чистый ответ. (в поддерживаемых системах). Спасибо.
Mtl Dev

7

Это должно работать на большинстве разновидностей Unix, BSD и Linux:

PATH=/usr/ucb:${PATH} ps aux | grep httpd | grep -v grep

Проверено на:

  • SunOS 5.10 [Отсюда PATH=... ]
  • Linux 2.6.32 (CentOS)
  • Linux 3.0.0 (Ubuntu)
  • Дарвин 11.2.0
  • FreeBSD 9.0-СТАБИЛЬНАЯ
  • Red Hat Enterprise Linux ES, выпуск 4
  • Red Hat Enterprise Linux Server, выпуск 5

2
+1 Да просто ps. Чтобы избежать второго, grepя предлагаю:ps aux | grep [h]ttpd
olibre

Я не использовал здесь трюк с квадратными скобками, чтобы упростить включение переменной в основную grep.
Johnsyweb 02

1
Хорошо;) Я только что тестировал на Red Hat AS 4 и Red Hat AP 5. Конечно, работаю! Итак, вы можете добавить в свой список: Red Hat Enterprise Linux ES выпуска 4 и Red Hat Enterprise Linux Server выпуска 5 . Cheers
olibre

@Downvoter: Почему? Что я пропустил? Насколько я могу судить, принятый ответ выполняет тот же поиск!
Johnsyweb

6

Самый простой способ - использовать ps и grep:

command="httpd"
running=`ps ax | grep -v grep | grep $command | wc -l`
if [ running -gt 0 ]; then
    echo "Command is running"
else
    echo "Command is not running"
fi

Если ваша команда имеет некоторые аргументы команды, вы также можете добавить больше «grep cmd_arg1» после «grep $ command», чтобы отфильтровать другие возможные процессы, которые вас не интересуют.

Пример: покажите мне, есть ли какой-либо java-процесс с предоставленным аргументом:

-Djava.util.logging.config.file = logging.properties

это работает

ps ax | grep -v grep | grep java | grep java.util.logging.config.file=logging.properties | wc -l

2
Фактически, использование ps caxустраняет необходимость использования grep -v. Так, например, вы можете использовать: ps cax | grep java > /dev/null || echo "Java not running".
Шоссе жизни

1
Ошибка в третьей строке. пожалуйста, измените "бег" на "$ бег".
Программист

5

Небольшое дополнение: если вы добавите -cфлаг в ps, вам не нужно grep -vвпоследствии удалять строку, содержащую процесс grep с . Т.е.

ps acux | grep cron

это все, что вам нужно для набора текста в системе bsd-ish (включая MacOSX). Вы можете оставить -u Если вам нужно меньше информации, .

В системе, где генетика собственной psкоманды указывает обратно на SysV, вы должны использовать

ps -e |grep cron

или

ps -el |grep cron 

для списка, содержащего не только идентификатор процесса и имя процесса. Конечно, вы можете выбрать определенные поля для печати, используя эту -o <field,field,...>опцию.


Насколько переносим этот ответ? (Вы говорите, что на разных платформах следует использовать разные формы команды ps)
peterh 03

ps, к сожалению, является одним из тех инструментов с другим набором опций для одного и того же результата в зависимости от их происхождения. Итак, если вы не напишете свою собственную (опять же несовместимую с чем-либо еще) оболочку вокруг этого, лучше всего будет знать основные линии наследия и соответствующим образом адаптироваться. Другое дело, когда вы пишете скрипт - вы можете использовать эти различия, чтобы определить, в какой ветке вы находитесь, и адаптировать поведение вашего скрипта. Итог: вам нужно знать и то, и другое. Известный пример: сценарий «configure» Ларри Уолла. Известная цитата: Поздравляю, вы не работаете с Юнис.
Татьяна Хойзер

5

Собрав вместе различные предложения, самая чистая версия, которую я смог придумать (без ненадежного grep, запускающего части слов):

kill -0 $(pidof mysql) 2> /dev/null || echo "Mysql ain't runnin' message/actions"

kill -0 не убивает процесс, но проверяет, существует ли он, а затем возвращает true, если у вас нет pidof в вашей системе, сохраните pid при запуске процесса:

$ mysql &
$ echo $! > pid_stored

затем в скрипте:

kill -0 $(cat pid_stored) 2> /dev/null || echo "Mysql ain't runnin' message/actions"

3

Я использую, pgrep -l httpdно не уверен, что он присутствует на какой-либо платформе ...
Кто может подтвердить на OSX?


Спасибо @Johnsyweb. Вы тоже можете проверить pidof? Хорошо, ты сделал. Спасибо. Так что мы должны найти что-нибудь еще, работающее на OSX ... Ваше основное ps|grepможет быть единственным решением ;-)
olibre

1

Вы должны знать PID вашего процесса.

Когда вы его запустите, его PID будет записан в $!переменной. Сохраните этот PID в файл.

Затем вам нужно будет проверить, соответствует ли этот PID запущенному процессу. Вот полный скелетный сценарий:

FILE="/tmp/myapp.pid"

if [ -f $FILE ];
then
   PID=$(cat $FILE)
else
   PID=1
fi

ps -o pid= -p $PID
if [ $? -eq 0 ]; then
  echo "Process already running."  
else
  echo "Starting process."
  run_my_app &
  echo $! > $FILE
fi

На основании ответа на peterh. Уловка, позволяющая узнать, работает ли данный PID, находится в ps -o pid= -p $PIDинструкции.


0

Такой подход можно использовать в случае, если команды ps, pidof и rest недоступны. Лично я очень часто использую procfs в своих инструментах / скриптах / программах.

   egrep -m1  "mysqld$|httpd$" /proc/[0-9]*/status | cut -d'/' -f3

Небольшое объяснение того, что происходит:

  1. -m1 - остановить процесс при первом совпадении
  2. "mysqld $ | httpd $" - grep будет соответствовать строкам, которые заканчиваются на mysqld ИЛИ httpd
  3. / proc / [0-9] * - bash будет соответствовать строке, начинающейся с любого номера
  4. вырезать - просто разделите вывод разделителем '/' и извлеките поле 3

0

Это печатает количество процессов, чье базовое имя - "Chrome-browser":

ps -e -o args= | awk 'BEGIN{c=0}{
 if(!match($1,/^\[.*\]$/)){sub(".*/","",$1)} # Do not strip process names enclosed by square brackets.
 if($1==cmd){c++}
}END{print c}' cmd="chromium-browser"

Если выводится «0», процесс не запущен. Команда предполагает, что путь к процессу не содержит разрывов. Я не тестировал это с приостановленными процессами или процессами зомби.

Протестировано с использованием gwakв качестве awkальтернативы в Linux.

Вот более универсальное решение с некоторыми примерами использования:

#!/bin/sh
isProcessRunning() {
if [ "${1-}" = "-q" ]; then
 local quiet=1;
 shift
else
 local quiet=0;
fi
ps -e -o pid,args= | awk 'BEGIN{status=1}{
 name=$2
 if(name !~ /^\[.*\]$/){sub(".*/","",name)} # strip dirname, if process name is not enclosed by square brackets.
 if(name==cmd){status=0; if(q){exit}else{print $0}}
}END{exit status}' cmd="$1" q=$quiet
}

process='chromium-browser'

printf "Process \"${process}\" is "
if isProcessRunning -q "$process" 
 then printf "running.\n"
 else printf "not running.\n"; fi

printf "Listing of matching processes (PID and process name with command line arguments):\n"
isProcessRunning "$process"

0

Вот моя версия. Особенности:

  • проверяет точное имя программы (первый аргумент функции). поиск "mysql" не будет соответствовать запущенному "mysqld"
  • ищет аргументы программы (второй аргумент функции)

сценарий:

#!/bin/bash

# $1 - cmd
# $2 - args
# return: 0 - no error, running; 1 - error, not running
function isRunning() {
    for i in $(pidof $1); do
        cat /proc/$i/cmdline | tr '\000' ' ' | grep -F -e "$2" 1>&2> /dev/null
        if [ $? -eq 0 ]; then
            return 0
        fi
    done
    return 1
}

isRunning java "-Djava.util.logging.config.file=logging.properties"
if [ $? -ne 0 ]; then
    echo "not running, starting..."
fi

0

Ни один из ответов у меня не сработал, поэтому вот мой:

process="$(pidof YOURPROCESSHERE|tr -d '\n')"
if [[ -z "${process// }" ]]; then
  echo "Process is not running."
else
  echo "Process is running."
fi

Пояснение:

|tr -d '\n'

Это удаляет возврат каретки, созданный терминалом. Остальное можно объяснить в этом посте.


-1

Следующая функция оболочки, основанная только на стандартных командах и параметрах POSIX, должна работать в большинстве (если не вообще) систем Unix и Linux. :

isPidRunning() {
  cmd=`
    PATH=\`getconf PATH\` export PATH
    ps -e -o pid= -o comm= |
      awk '$2 ~ "^.*/'"$1"'$" || $2 ~ "^'"$1"'$" {print $1,$2}'
  `
  [ -n "$cmd" ] &&
    printf "%s is running\n%s\n\n" "$1" "$cmd" ||
    printf "%s is not running\n\n" $1
  [ -n "$cmd" ]
}

$ isPidRunning httpd
httpd is running
586 /usr/apache/bin/httpd
588 /usr/apache/bin/httpd

$ isPidRunning ksh
ksh is running
5230 ksh

$ isPidRunning bash
bash is not running

Обратите внимание, что он задыхается при передаче сомнительного имени команды «0]», а также не сможет идентифицировать процессы, в именах которых есть пробелы.

Также обратите внимание, что наиболее популярное и принятое решение требует непереносимых psопций и безвозмездно использует оболочку, которая, несмотря на ее популярность, не гарантированно присутствует на каждой машине Unix / Linux ( bash)


$ isPidRunning 0]выводит, например, «0] выполняется 3 [ksoftirqd / 0] 8 [rcuop / 0] 17 [rcuos / 0] 26 [rcuob / 0] 34 [migration / 0] 35 [watchdog / 0]» здесь.
Ярно

Для чего вам нужен этот PATH?
Ярно

Я разработал решение здесь .
Ярно

@jarno Параметр PATH необходим для переносимости сценария. В противном случае он потерпит неудачу, по крайней мере, в Solaris 10 и старше и, возможно, в других реализациях Unix.
jlliagre

1
@jarno Я мог бы это сделать, но мне нужно будет повторить эту настройку PATH и для awk. Обратите внимание, что я вернулся к старому синтаксису обратной кавычки, чтобы быть переносимым с оболочками bourne синтаксиса до POSIX.
jlliagre
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.