Як перевірити, чи існує ідентифікатор процесу (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
Переглядаючи сторінку man, 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: У такому випадку він все одно не може його вбити.
Крістофер Хаммарстрем

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 в баші ".

Метод / proc цікавий, але в деякому сенсі порушує дух абстракції команди "ps", тобто вам не потрібно заходити шукати / proc, бо що робити, якщо Лінус вирішить викликати файл "exe" чимось іншим?


1
ps -p завжди повертає для мене статус 0
IttayD

1
ps -p #### прекрасно працював для мене під Ubuntu 14.04, +1 спасибі!
Ligemer

3
ps -p завжди повертає код статусу 0 в os x, оскільки він друкує порожній список процесу, коли він не відповідає жодному запущеному процесу
Douglas Correa

Я можу підтвердити, що на macOS Sierra це працює. Крім того, -pнепотрібне, принаймні в такому випадку. ps $PIDмає точно такий же результат.
користувач137369

Переносність - це вагомий привід уникати використання / 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дав дійсний результат.


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
Will

На жаль, psваріанти та функції, як правило, відрізняються між платформами, тому це все ще не повністю портативно.
трійка

1
якщо $PIDпорожній, то [ -e /proc/$PID ]все одно поверне справжнє значення, оскільки /proc/каталог все ще існує.
Магне

34

psкоманда з -p $PIDможе зробити це:

$ ps -p 3531
  PID TTY          TIME CMD
 3531 ?        00:03:07 emacs

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" та натисніть на 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", як описано в інших відповідях.


принаймні, частина 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тому, що він буде працювати, навіть якщо у вас немає власного підручника).


1
чекати не настільки ефективно, оскільки процес повинен бути дочірньою оболонкою, або він дасть:pid 123 is not a child of this shell
Calumah

7

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


На жаль, код виходу (1) kill (1) не відрізняє різних ситуацій помилок (схоже, він збільшує значення виходу на одиницю для кожного процесу, про який не вдалося подати сигнал). якщо ОП не проти написати написання власної оболонки kill (2), він може дати йому вихід з різними значеннями на основі значення ERRNO після невдалого виклику kill (2).
просто хтось

на даний момент я просто роблю вбивство -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 існує, але використовується іншим додатком, це може призвести до «непередбачених наслідків».


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

і це показує назву програми, а саме ім'я без ідентифікатора.


1
pidofне повертає негативне число, оскільки від'ємний PID не має жодного сенсу, і ви не можете вбити init, тому ваш умовний сенс не має сенсу (і крім того, вам потрібно буде уникнути, >щоб запобігти його переадресації). Ви хочете перевірити наявність порожнього результату, але, звичайно, як і будь-який пристойний інструмент, pidofвстановлює код виходу, щоб повідомити, чи спрацювало воно, тож правильне рішення - if Pid=$(pidof 'process_name'); then ...або (якщо вам не знадобиться значення Pidзгодом), простоif pidof 'process_name'; then...
tripleee

@tripleee має рацію, pidofприклад насичений непорозуміннями щодо того, як testпрацює баш . 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 $?
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.