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

184

В скрипте bash я хочу сделать следующее (в псевдокоде):

if [ a process exists with $PID ]; then

    kill $PID 

fi

Какое выражение подходит для условного оператора?

Ричард Х
источник

Ответы:

182

Чтобы проверить наличие процесса, используйте

kill -0 $pid

Но, как сказал @unwind, если вы все равно собираетесь его убить, просто

kill $pid

или у вас будет состояние гонки.

Если вы хотите игнорировать вывод текста killи делать что-то на основе кода выхода, вы можете

if ! kill $pid > /dev/null 2>&1; then
    echo "Could not send SIGTERM to process $pid" >&2
fi
Кристоффер Хаммарстрём
источник
1
Если посмотреть на справочную страницу, kill -0 это: «Код выхода указывает, может ли быть отправлен сигнал». Так действительно ли это убивает процесс или просто говорит вам, можно ли его убить?
Ричард Х
24
killнесколько неверно назван тем, что он не обязательно убивает процесс. Он просто отправляет процессу сигнал. kill $PIDэквивалентно тому kill -15 $PID, что посылает сигнал 15, SIGTERM процессу, который является инструкцией для завершения. Сигнала 0 нет, это специальное значение, killуказывающее просто проверить, может ли сигнал быть отправлен процессу, что для большинства целей более или менее эквивалентно проверке, существует ли он. См. Linux.die.net/man/2/kill и linux.die.net/man/7/signal
Кристоффер Хаммарстрем
43
Проблема заключается в том, что если процесс не принадлежит запущенному пользователю, у вас могут не быть разрешения на вызов kill -0. Лучше использовать ps -p $ PID> / dev / null 2> & 1, который позволяет вам видеть состояние процесса, даже если у вас нет прав для отправки сигнала.
mckoss
6
@mckoss: в этом случае он все равно не может убить его.
Christoffer Hammarström
2
Итак, я думаю - чтобы использовать kill -0, я, фактически, должен сделать это: kill -0 25667 ; echo $?- и тогда, если я получу 0возвращенный, тогда процесс с этим PID может быть остановлен; и если PID процесса (скажем) не существует, $?будет 1указывать сбой. Это правильно?
sdaau
264

Лучший способ это:

if ps -p $PID > /dev/null
then
   echo "$PID is running"
   # Do something knowing the pid exists, i.e. the process with $PID is running
fi

Проблема с:

kill -0 $PID

код выхода будет ненулевым, даже если pid запущен и у вас нет разрешения на его уничтожение. Например:

kill -0 1

и

kill -0 $non-running-pid

иметь обычный неотличимый (ненулевой) код завершения для обычного пользователя, но процесс init (PID 1), безусловно, выполняется.

ОБСУЖДЕНИЕ

Ответы, обсуждающие условия убийства и расы, являются абсолютно правильными, если тело теста является «убийством». Я пришел в поисках общего " как вы проверяете наличие PID в Bash ".

Метод / proc интересен, но в некотором смысле нарушает дух абстракции команды «ps», т. Е. Вам не нужно искать в / proc, что, если Линус решит назвать файл «exe» чем-то другим?

FDS
источник
1
ps -p всегда возвращает мне статус 0
IttayD
1
ps -p #### у меня нормально работал под Ubuntu 14.04, +1 спасибо!
Ligemer
3
ps -p всегда возвращает код состояния 0 в os x, потому что он печатает пустой список процессов, когда он не соответствует ни одному из запущенных процессов
Дуглас Корреа
Я могу подтвердить, что на macOS Sierra это работает. Кроме того, в -pэтом нет необходимости, по крайней мере, в этом случае. ps $PIDимеет точно такой же результат.
user137369
Переносимость - хорошая причина, чтобы избегать использования / proc, но linux, нарушающий его ABI, - это не тот сценарий, о котором я бы особенно беспокоился.
Дэвид
67
if [ -n "$PID" -a -e /proc/$PID ]; then
    echo "process exists"
fi

или

if [ -n "$(ps -p $PID -o pid=)" ]

В последней форме -o pid=- выходной формат для отображения только столбца идентификатора процесса без заголовка. Кавычки необходимы для оператора непустой строки, -nчтобы дать правильный результат.

user2683246
источник
1
Второй метод также работает на Mac, как дополнительный плюс (Mac OS X не имеет / proc FS). Однако вы можете избежать использования подоболочки и использовать ее как на Mac, так и на Linux:if ps -p"$PID" -o "pid=" >/dev/null 2>&1; then echo "Process is running..."; fi
Будет ли
К сожалению, psпараметры и функции, как правило, различаются для разных платформ, поэтому они все еще не полностью переносимы.
tripleee
1
Если $PIDпуст, то [ -e /proc/$PID ]все равно вернет истину, так как /proc/каталог все еще существует.
Магне
34

psкоманда с -p $PIDможет сделать это:

$ ps -p 3531
  PID TTY          TIME CMD
 3531 ?        00:03:07 emacs
oherrala
источник
11

У вас есть два пути:

Начнем с поиска конкретного приложения на моем ноутбуке:

[root@pinky:~]# ps fax | grep mozilla
 3358 ?        S      0:00  \_ /bin/sh /usr/lib/firefox-3.5/run-mozilla.sh /usr/lib/firefox-3.5/firefox
16198 pts/2    S+     0:00              \_ grep mozilla

Все примеры сейчас будут искать PID 3358.

Первый способ : Запустите «ps aux» и grep для PID во втором столбце. В этом примере я ищу Firefox, а затем его PID:

[root@pinky:~]# ps aux | awk '{print $2 }' | grep 3358
3358

Итак, ваш код будет:

if [ ps aux | awk '{print $2 }' | grep -q $PID 2> /dev/null ]; then
    kill $PID 
fi

Второй способ : просто поищите что-нибудь в /proc/$PIDкаталоге. Я использую «exe» в этом примере, но вы можете использовать что-нибудь еще.

[root@pinky:~]# ls -l /proc/3358/exe 
lrwxrwxrwx. 1 elcuco elcuco 0 2010-06-15 12:33 /proc/3358/exe -> /bin/bash

Итак, ваш код будет:

if [ -f /proc/$PID/exe ]; then
    kill $PID 
fi

Кстати, что не так с kill -9 $PID || true?


РЕДАКТИРОВАТЬ:

Подумав об этом в течение нескольких месяцев ... (около 24 ...) оригинальная идея, которую я привел здесь, - хороший хак, но крайне непереносимый. Хотя он учит некоторые детали реализации Linux, он не сможет работать на Mac, Solaris или * BSD. Это может даже не сработать в будущих ядрах Linux. Пожалуйста, используйте «ps», как описано в других ответах.

elcuco
источник
по крайней мере, часть kill -9 кажется неправильной (не убивает подпроцессы)
nurettin
Почему я получаю [: отсутствующий `] 'при использовании первого способа?
десять минут
1
/proc/$PID/exeэто не обычный файл. Таким образом, [ -f /proc/$PID/exe ]всегда возвращает falseрезультат. Попробуй [ -h /proc/$PID/exe ].
Александр Янчарук
8

Кажется, ты хочешь

wait $PID

который вернется, когда $pidзакончит.

В противном случае вы можете использовать

ps -p $PID

проверить, если процесс еще жив (это более эффективно, чем kill -0 $pidпотому, что он будет работать, даже если у вас нет pid).

Гаган Гами
источник
1
ожидание не так эффективно, так как процесс должен быть дочерним по отношению к текущей оболочке, или он даст:pid 123 is not a child of this shell
Калума
7

Я думаю, что это плохое решение, которое открывается для условий гонки. Что если процесс умирает между вашим тестом и вашим призывом убить? Тогда убить не удастся. Так почему бы просто не попробовать kill во всех случаях и проверить ее возвращаемое значение, чтобы выяснить, как все прошло?

размотать
источник
+1, к сожалению, код выхода kill (1) не различает различные ситуации ошибки (похоже, он увеличивает значение выхода на единицу для каждого процесса, о котором он не сообщил). если OP не возражает написать свою собственную оболочку kill (2), он может заставить ее выйти с другими значениями, основанными на значении ERRNO после неудачного вызова kill (2).
просто кто-то
в данный момент я просто выполняю kill -9 без проверки - я просто получаю сообщение об ошибке «процесс не существует», если он не существует, что не очень аккуратно. Как бы я проверить, что случилось?
Ричард Х
14
Не небрежно kill -9. Это просто мгновенно убивает процесс, не давая ему возможности убирать за собой. Вместо этого используйте killчто эквивалентно kill -15. Если это не сработает, вы должны выяснить, почему, и только в крайнем случае kill -9.
Кристоффер Хаммарстрем
0

здесь я сохраняю PID в файле с именем .pid (что-то вроде / run / ...) и выполняю сценарий, только если он еще не выполняется.

#!/bin/bash
if [ -f .pid ]; then
  read pid < .pid
  echo $pid
  ps -p $pid > /dev/null
  r=$?
  if [ $r -eq 0 ]; then
    echo "$pid is currently running, not executing $0 twice, exiting now..."
    exit 1
  fi
fi

echo $$ > .pid

# do things here

rm .pid

примечание: есть состояние гонки, поскольку оно не проверяет, как называется этот pid. если система перезагружена и .pid существует, но используется другим приложением, это может привести к «непредвиденным последствиям».

invalidmagic
источник
0

Например, в GNU / Linux вы можете использовать:

Pid=$(pidof `process_name`)

if [ $Pid > 0 ]; then

   do something
else

   do something
fi 

Или что-то вроде

Pin=$(ps -A | grep name | awk 'print $4}')
echo $PIN

и это показывает вам имя приложения, просто имя без идентификатора.

inukaze
источник
1
pidofне возвращает отрицательное число, так как отрицательный PID не имеет никакого смысла, и вы не можете убить init, поэтому ваше условное выражение не имеет смысла (и, кроме того, вам нужно будет экранировать, >чтобы предотвратить перенаправление). Вы хотите проверить наличие пустого результата, но, конечно, как и любой приличный инструмент, pidofустанавливает код выхода, чтобы сообщить вам, сработал ли он, поэтому правильное решение - if Pid=$(pidof 'process_name'); then ...или (если вам не понадобится значение в Pidдальнейшем) простоif pidof 'process_name'; then...
tripleee
@tripleee прав, pidofпример полон недоразумений о том, как testработает bash . gnu.org/software/bash/manual/html_node/…
Бруно Броноски
0

Приведенный ниже код проверяет, работает ли мой процесс, если это не так, ничего не делайте.

давайте проверять новые сообщения от Amazon SQS только каждый час и только если процесс не запущен.

#!/bin/bash
PID=$(ps aux | grep '/usr/bin/python2.7 manage.py SES__boto3_sqs_read' | grep -v grep | awk '{print $2}')
if [[ -z $PID ]]; then
    /usr/bin/python2.7 /home/brian/djcode/proyectoONE/manage.py SES__boto3_sqs_read
else
    echo "do nothing, just smile =)"
fi
exit $?
Брайан Санчес
источник