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

У меня есть говорящие часы, использующие eSpeak.

В вашем случае может помочь, если вы добавите идентификатор пользователя, который должен воспроизводить звуки, в группу аудио (в конце строки, начинающейся с audio, в файле /etc/group).

Так что добавьте root, если вы хотите, чтобы он воспроизводился через sudo crontab -e. (Это было необходимо только для меня с обычными идентификаторами пользователей (, а не для root), но это может отличаться в разных дистрибутивах Linux.)

3
06.11.2020, 22:56
5 ответов

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

➜  ~ vim test.txt &
[1] 5634
➜  ~
[1]  + 5634 suspended (tty output)  vim test.txt
➜  ~ jobs
[1]  + suspended (tty output)  vim test.txt
➜  ~ kill -9 5634
[1]  + 5634 killed     vim test.txt
➜  ~ jobs
➜  ~

В этом случае vim test.txtнаходится во втором столбце и может использоваться для проверки того, что процесс остается прежним и программа является правильной. Если jobsне возвращает целевую программу, вы можете изменить свою скрипт, чтобы не убить PID.

0
18.03.2021, 23:03

Как было сказано в комментариях, утилита pkillможет оказаться полезной.

Поскольку вы говорите "скрипт bash", вам, скорее всего, придется запуститьpkill bash-А этого делать не следует.

Вместо этого вы можете использовать pkill -f <name>, который будет использовать полное имя процесса для соответствия. Итак, предполагая, что ваша задача bash /home/me/my_script.sh, вы можете использовать следующее:

pkill -f -e my_script.sh

Параметр -eявляется необязательным и просто выводит то, что было убито.


Альтернатива:

Сохраните следующий скрипт как/usr/bin/mykill(или куда угодно):

#!/bin/bash
mypid="$1"
if [[ ! -f /proc/$mypid/cmdline ]]; then
    echo "Process ID not found."
    exit 1
else
    echo "About to kill $(cat /proc/$mypid/cmdline)"
    echo "Press enter if you want to kill that process"
    read -p "Press CTRL-C if you don't want that"
    kill $mypid
fi

И запустите какmykill <pid>

2
18.03.2021, 23:03

Надежного способа сделать это не существует.

Поскольку идентификаторы PID являются глобальными повторно используемыми идентификаторами, их использование по своей сути неприемлемо. Но то, как реализованы оболочки, делает это намного хуже, :оболочка пожинает плоды своих детей жадно , т.е. она вызывает системный вызов waitpid(), как только они умерли, и сохраняет их PID и статус где-то в памяти.Фоновые задачи, запущенные как foo &, НЕ задерживаются как процессы-зомби, пока вы не вызовете встроенную команду wait. Возможно, PID уже использовался повторно, так как вы получили его с помощью команд jobsили pgrep.

Ваша лучшая надежда состоит в том, чтобы сократить временной интервал, в течение которого PID могут быть повторно использованы, и свести к минимуму риски. Как было предложено, вы можете использовать pkillвместо явного уничтожения по PID. Особенно полезен его -Pфлаг ("выбрать по родителю" ), отсюда

pkill -P "$$"
5
18.03.2021, 23:03

Если ваш фоновый процесс находится под вашим контролем, добавьте дополнительную идентификацию в его командную строку в виде метки, копию которой вы можете сохранить вместе с PID, а позже проверить в ps -o args myPid.

Я использую такой вариант, как--unique "${myTag}"

Я получаю myTag либо из uuidgen, либо из dateс точностью до наносекунд. Если это задание ssh, укажите локальное имя хоста.

Если вы не можете ввести новую опцию:

.. Используйте date +%s, чтобы получить время начала задания и сохранить его вместе с Pid.

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

.. Сравните с текущим date +%s(, вероятно, с допуском в несколько секунд ).

Любой метод в сочетании с PID должен иметь пренебрежимо малую вероятность ошибки.

2
18.03.2021, 23:03

Я не согласен с тем, что это вообще невозможно. И я бы не рекомендовал убивать по имени -с помощью pkill, если вы можете этого избежать (что, если вы законно хотите, чтобы несколько экземпляров какой-либо команды имели индивидуальные тайм-ауты? ). Я не понимаю, как ответ относительно jobsвообще что-то делает для устранения состояния гонки; с использованием jobs, а затем killне является атомарным.

Тем не менее, мы можем использовать идентификаторы группы процессов(PGIDс ), если управление заданиями включено, или использовать подоболочку и уничтожить идентификатор родительского процесса (PPID), если это невозможно. Смотрите мой пост здесь:https://unix.stackexchange.com/a/649320/464414

Я приведу только выдержку из предпочтительного метода и вставлю его сюда; см. сообщение выше для заметок и альтернатив.

ОБНОВЛЕНО :Версия ниже теперь работает с трубами

timeOut() {
    checkArgs() { [ $(( ${1} )) -gt 0 -a "${*:2}" ]; }
    jobControlEnabled() { expr "${-}" : '.*m' >/dev/null; }
    terminalFDs() { [ -t 0 -a -t 1 ]; }
    groupLeader() { sh -c 'expr `ps -o pgid= ${PPID}` : "${PPID}" >/dev/null;'; }
    timeOutImpl() {
        groupLeader || { echo "Job control error - not group leader!"; return -1; }
        KILL_SUB="kill -- -`sh -c 'echo ${PPID}'`"
        { sleep ${1}; ${KILL_SUB}; } &
        "${@:2}"; ${KILL_SUB}
    }
    checkArgs "${@}" || { echo "Usage: timeOut <delay> <command>"; return -1; }
    if jobControlEnabled && terminalFDs; then
        ( timeOutImpl "${@}"; )
    else
        ( set -m; ( timeOutImpl "${@}"; ); )
    fi
}
0
12.05.2021, 04:43

Теги

Похожие вопросы