LINUX.ORG.RU

Запустить процесс, а потом его найти и убить

 


1

2

Суть описана в заголовке. Проблема, как вы уже догадались, в том, что процесс может успешно сдохнуть сам. Сейчас я просто беру pid процесса и засовываю его в файл. Потом делаю kill. И это - ужасно. Демона из него делать не нужно. По идее надо просто чистить файл с pid, если процесс сдох. Но как это сделать, я что-то не догоняю. Если вынести процесс в отдельный скрипт (в котором чистить файл после завершения) то при запуске получишь pid скрипта, а он - не нужен.
Пример

#run.sh
mycoolprocess &
PID=$!
echo $PID > my.pid

#stop.sh
kill $(cat my.pid)
>my.pid

upd: решено через еще один скрипт и убийство этого самого скрипта с потомками.

Если выносить процесс в отдельный скрипт, то идти до конца, и давать скрипту и имя файла, куда нужно записать pid процесса, как делается у демонов.

Зачем чистить файл, если процесс сдох не понятно, kill на несуществующий pid, это разве страшно? А если бояться, что под этим pid'ом появится другой процесс, то проверять его имя или ещё что, перед вызовом kill.

mky ★★★★★ ()

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

madcore ★★★★★ ()
Ответ на: комментарий от mky

Зачем чистить файл, если процесс сдох не понятно, kill на несуществующий pid, это разве страшно? А если бояться, что под этим pid'ом появится другой процесс, то проверять его имя или ещё что, перед вызовом kill.

Страшно и не приятно. Имя чекать не охота, хочется как-то проще.

Если выносить процесс в отдельный скрипт, то идти до конца, и давать скрипту и имя файла, куда нужно записать pid процесса, как делается у демонов.

Может мне pid самого процесса таки не нужен и можно просто грохнуть скрипт из которого он запускается?

crutch_master ★★★★★ ()
Ответ на: комментарий от madcore

Почему обёрточный скрипт не может сохранять пид твоего процесса?

Он же и удалит файл с пидом, без разницы сам тот завершился или был убит. Я сделал так:

#run.sh
./start.sh &
PID=$!
echo $PID > my.pid

#start.sh
mycoolprocess
>my.pid

#stop.sh
kill $(cat my.pid)
>my.pid
Это норм? Если я грохну start.sh по pid'у процесс запущенный из него сдохнет?

crutch_master ★★★★★ ()
Последнее исправление: crutch_master (всего исправлений: 1)
Ответ на: комментарий от mky

.А если бояться, что под этим pid’ом появится другой процесс, то проверять его имя или ещё что, перед вызовом kill.

А если старый процесс умрет и появится новый с этим pid между этой проверкой и kill, то юзать новый API для отправки сигналов через procfs…

t184256 ★★★★★ ()
Ответ на: комментарий от vodz

Читаем. http://laurvas.ru/bash-trap/

$ cat trap.sh 
#!/bin/bash

trap 'echo trap SIGINT' SIGINT
trap 'echo trap SIGTERM' SIGTERM
trap 'echo trap SIGHUP' SIGHUP
trap 'echo trap SIGQUIT' SIGQUIT
trap 'echo trap EXIT' EXIT
trap 'echo trap ERR' ERR

echo 'start'
sleep 1m
echo 'end'

$ ./trap.sh &
[1] 18299
start
$ kill -SIGINT 18299
$ #nothing
$ kill -SIGINT %1
trap SIGINT
trap ERR
end
trap EXIT
[1]+  Готово            ./trap.sh
$ echo $BASH_VERSION
4.3.11(1)-release

И как послать ему sigint по pid, чтобы сработал trap?

crutch_master ★★★★★ ()
Последнее исправление: crutch_master (всего исправлений: 1)

смотреть какая прога запущена по PID ??

$ cat /proc/%PID%/cmdline

$ readlink -f /proc/%PID%/exe

но для баша ссыль будет на сам баш, так что непонтяно твой илине твой командник гоняется.
но баш обычно засовывает линк на командый файл в 254 поток.

можно сравнивать нужный ли командный файл тудысь вписан.

$ readlink -f /proc/%PID%/fd/254

а лучше воспользоваться системд, он пристреливает по вхождению в cgroup и без разницы кто в чего форкнулся и сколько раз.

pfg ★★ ()
Ответ на: комментарий от pfg

но для баша ссыль будет на сам баш, так что непонтяно твой илине твой командник гоняется.
но баш обычно засовывает линк на командый файл в 254 поток.

Гадание на кофейной гуще. Я не могу гарантировать, что там не будет процесса с таким же названием.

а лучше воспользоваться системд

У меня нет времени сношаться еще и с системд.

crutch_master ★★★★★ ()
Последнее исправление: crutch_master (всего исправлений: 1)

Workaround через pgrep:

#run.sh
./start.sh &
PID=$!
echo $PID > my.pid

#start.sh
mycoolprocess
>my.pid

#stop.sh
pid=$(cat my.pid)
cpid=$(prgep -P $pid)
kill $cpid
kill $pid # не обязательно
>my.pid
Вроде работает, но почему trap не работает с kill pid всё равно интересно.

crutch_master ★★★★★ ()

Есть много способов проверить, принадлежит ли pid тому процессу, который запускался.

Можно запихнуть процесс в какую-то cgroups, и потом проверить /proc/$PID/cgroup на наличие в соответствующей группе. Так делает systemd:

  mkdir /sys/fs/cgroup/memory/myprecious
  echo $PID > /sys/fs/cgroup/memory/myprecious/tasks

Можно заставить процесс держать определённый дескриптор, а в stop.sh проверить, держит ли он его. Так делает daemontools (man fghack):

mycoolprocess 777>/dev/null &
PID=$!
...
[ -e /proc/$PID/fd/777 ] && kill $PID

Можно выставит процессу какую-нибудь переменную, и в stop.sh проверить, что она выставлена:

STARTED_BY_ME=12345 mycoolprocess &
...
grep -q STARTED_BY_ME=12345 /proc/$PID/environ && kill $PID

В принципе, можно много чего проверить, имя, sid или ppid процесса...

Я предпочитаю запоминать время запуска процесса (man 5 proc), и проверять его:

STARTUPTIME=$(awk -v RS=')' 'END{print $20}' /proc/$PID/stat)
Если на том же PID-е и запустится другой процесс, то время запуска точно изменится.

PS: кроме того рекомендую обратить внимание на nohup и disown

anonymous ()
Ответ на: комментарий от anonymous

Ага, там рут еще нужен, и логи оно пишет куда-нибудь себе, и еще какие-нибудь ямы с дерьмом. Спасибо. Лучше уж костыли. Я их хотя бы контролирую, в отличии от системд.

crutch_master ★★★★★ ()
Последнее исправление: crutch_master (всего исправлений: 2)
Ответ на: комментарий от anonymous

изобретает костыль за костылём

Справедливости ради, это systemd изобретает костыли (cgroups), а потом другие костыли чтобы закрыть баги в этих костылях (pam_systemd). А в шелл-скриптах всё давно изобретено до нас. Posix shell старше и systemd и его автора.

anonymous ()
Ответ на: комментарий от crutch_master

Вроде работает, но почему trap не работает с kill pid всё равно интересно.

Потому, что при вызове внешней программы (sleep) обработчики сигналов самого shell-а устанавливаются в принятые для shell-ов по умолчанию. Причём, «для shell-ов» — это важно. Ибо общепринято по TERM/INT убиваться всем процессам по умолчанию, но оставаться живым shell-ам. Если вы замените sleep на что-то встроенное, скажем на while true;, то тогда сигнал обработается уже trap-ом, так как вы его настроили и не вызвали внешнюю прогу. kill же, как встроенная программа в shell по имени задачи посылает сигнал процессу как родоначальнику группе процессов, потому система посылает его всем процессам, родоначальник которого есть указанный. То есть это аналогично вызову kill -SIGINT -pid

vodz ★★★★ ()
Последнее исправление: vodz (всего исправлений: 3)
Ответ на: комментарий от vodz

Вот тут. kill -SIGINT %1 работает, kill -SIGINT $pid не работает. Почему? Как сделать так, чтобы trap сработал, если в скрипте запущен внешний процесс?

crutch_master ★★★★★ ()
Последнее исправление: crutch_master (всего исправлений: 1)
Ответ на: комментарий от vodz

Вы повторяете вопрос, в постинге на который дано развернутое объяснение и решение.

Я не могу поменять процесс на while true; мне нужен процесс, это - не решение. Вы таки сами предложили использовать trap, я протрахался с ним 2 часа, а результата таки нет. Так что давайте, показывайте свой вариант скрипта с trap, уважаемый.

crutch_master ★★★★★ ()
Ответ на: комментарий от crutch_master

Так что давайте

С чего это? Я и так потратил на вас кучу времени и всё разжевал. Что непонятного в том, что если вы хотите извращаться и писать демона на shell, то надо приготовиться убивать его не по kill pid, а по kill -pid?

vodz ★★★★ ()
Ответ на: комментарий от vodz

С чего это? Я и так потратил на вас кучу времени и всё разжевал.
разжевал

$ ./trap.sh &
[1] 27430
$ kill -SIGINT -pid 27430
bash: kill: -pid: аргументы должны быть идентификаторами процесса или задачи
$ kill -pid 27430
bash: kill: pid: недопустимая спецификация сигнала

Не тратьте в следующий раз своё драгоценное время, чтобы так разжевывать. И без вас бы разобрались. Спасибо.

crutch_master ★★★★★ ()
Ответ на: комментарий от crutch_master

Дядя, вы дурак? Как можно понять запись kill -SIGINT -pid как kill -SIGINT -pid 27430, а не как kill -SIGINT -27430?

И без вас бы разобрались.

Ну да, тут желающих постебаться над неумеющих читать man достаточно. Желаете валяться в дерьме - наздоровье.

vodz ★★★★ ()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от vodz

Как можно понять запись kill -SIGINT -pid как kill -SIGINT -pid 27430, а не как kill -SIGINT -27430?

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

anonymous ()
Ответ на: комментарий от vodz

Как можно понять запись kill -SIGINT -pid как kill -SIGINT -pid 27430, а не как kill -SIGINT -27430?

А почему бы её и не понять, как kill -pid 27430? Может всё таки стоит писать какой-нибудь пример?

Ну да, тут желающих постебаться над неумеющих читать man достаточно. Желаете валяться в дерьме - наздоровье.

Да вы тут, вроде, один такое дело любите. Анон выже привёл кучу примеров. Вы подумайте над тем, что не только для меня это всё тут пишете.

crutch_master ★★★★★ ()
Ответ на: комментарий от crutch_master

Да вы тут, вроде, один такое дело любите.

Дядя. Вам в доброжелательной форме разжевали и man и поведение системы и дали КОНКРЕТНЫЙ пример. Ну протормозили, ну с кем не бывает. Но хамить на тот ответ может только откровенный мудак.

vodz ★★★★ ()
Ответ на: комментарий от vodz

Но хамить на тот ответ может только откровенный мудак

Уважаемый, где вам хамят, покажите пожалуйста. И извините, пожалуйста, что ваши советы оказались не слишком полезны.

дали КОНКРЕТНЫЙ пример

- $ kill -SIGINT 18299
+ $ kill -SIGINT -18299

Вот это - КОНКРЕТНЫЙ пример. Делайте лучше так, не стоит испытывать парсер других людей на прочность. Этим вы сэкономите всем время. Спасибо.

crutch_master ★★★★★ ()
Ответ на: комментарий от crutch_master

Анон выже привёл кучу примеров. Вы подумайте над тем, что не только для меня это всё тут пишете.

Ну ладно вам. Его ответ очень даже ценен, тем более, что этой информации в одном месте нет.

К тому же его ответ хорош тем, что заставляет читать документацию. Меня он заставил перечитать секцию SIGNALS в man bash, а также man 2 setpgid, man 2 setsid, документацию по Process group, и что с ними происходит при завершении лидера (Sessions and Process Groups).

Просто не у всех есть час свободного времени на составление подробного сообщения с примерами. У меня этот час был, у него не было.

anonymous ()

создавай и чисти пидфайл прямо в своем процессе. килл перехватывай и все равно чисти файл при завершении. если прибьют по -9, ну да, не почистится, селяви.

anto215 ()
Ответ на: комментарий от crutch_master

Я ещё чуть-чуть добавлю.

kill -SIGINT $pid не работает. Почему?

А он работает, просто обработчик вызвать не может, потому что шелл занят выполнением sleep-а. Когда sleep закончится, и управление вернётся в шелл, тогда и вызовется обработчик trap SIGINT (это описано в man bash в секции SIGNALS)

kill -SIGINT %1 работает

Потому что это — не то же самое! kill -SIGINT %1 отправляет сигнал не одному процессу, а всем процессам группы. Всё остальное работает так же: обработчик вызывается после того, как завершится sleep. Но теперь sleep тоже получает сигнал, и завершается сразу, потому и обработчик тоже вызывается сразу, не приходится ждать срабатывания целую минуту (сходу не знаю, где в мане это описано, так что спасибо vodz, что обратил на это внимание)

Ну а остальное уже написали.

anonymous ()
Ответ на: комментарий от anto215

создавай и чисти пидфайл прямо в своем процессе

Таки да, это он сдохнет, а он часто дохнет, то селяви. Уже решили через еще один скрипт и его убийством вместе с потомками.

crutch_master ★★★★★ ()

Я офигеваю с треда, если честно. И это тот лор, который везде считают гнездилищем агрессивных красноглазиков?

Дали правильный ответ про симтемд; когда ТС начал воротить нос дали другое решение «по старинке» объяснили как работает; ТС сморщил щячло на тему «не так объяснили»; переобъяснили по-новой.

Сплошная дружбомагия, никаких «сделай как Томми» и «в биореактор», анон вежливее, чем клерки в банке. Что произошло? CoC приняли? Альтруизин распылили, а на ТСа не попало? Поразительно.

legolegs ★★★★★ ()
Последнее исправление: legolegs (всего исправлений: 1)
Ответ на: комментарий от crutch_master

Страшно и не приятно. Имя чекать не охота, хочется как-то проще.

Хоть вопрос и отмечен решённым, всё же отвечу.
Мне всегда идея сохранения PID'а в файл и мониторинга/завершения по этому PID'у казалась несколько ненадёжной. Может быть, процесс уже завершился, а PID достался другому? Поэтому возникла такая идея: процесс, который надо запускать, завершать, мониторить и т.п. должен держать PID-файл открытым. Процесс запускается, проверяет, не открыт ли PID-файл, если нет, то открывает и держит до своего завершения. Например, на bash'е я это сделал так:

function main ()
{
    echo .......
}

function checkRunning ()
{
    for pid in `pidof bash`
    do
        ls -l /proc/$pid/fd/|grep $pidfile >/dev/null && echo "Error message !!!" && exit 1
    done
}

function lockPid ()
{
    echo $$ > $pidfile
    exec 4<> $pidfile
}

function clearPid ()
{
    exec 4<&-
    rm $pidfile
}

pidfile="/run/some/name/here.pid"

checkRunning
lockPid
main
clearPid
Соответственно, в других скриптах, так же можно проверять, какой процесс держит этот файл открытым.

ls-h ★★★ ()

Решение на основе утилиты ps

Есть такая утилита для вывода информации о процессах, называется она ps
Так вот её опции позволяют очень гибко настраивать её вывод, уверен что можно сделать так, что она будет выводить только имя процесса.

Ну значит когда придёт время убивать процесс спрашиваешь у этой утилиты какое имя имеет процесс pid такой то, если то какое надо то убиваешь этот процесс, иначе ошибка.

К стати выводит она не только имя, но и другие параметры, думаю что проверку можно как ни будь уточнить, например поставить метку не каналом, как предложил выше anonymous, а добавив какую нибудь опцию-метку в строку запуска утилиты.

Конкретные опции писать не буду, разберёшся прочитав man этой утилиты.

torvn77 ★★★★ ()
Последнее исправление: torvn77 (всего исправлений: 1)
Ответ на: Решение на основе утилиты ps от torvn77

Я почитал мануальник, нужный результат получил.

П.С. Там есть хорошая опция ppid выводящая pid родительского процесса, думаю тебе она тоже пригодится.

torvn77 ★★★★ ()
Последнее исправление: torvn77 (всего исправлений: 1)