Передайте SIGTERM ребенку в Bash

Для поиска определенного PID, я вызвал бы pstree -p которые визуализируют отношение процессов. С этим главным образом возможно сузить все имеющие право процессы.

Этот подход предполагает, что рассматриваемое окно является, по крайней мере, дочерним элементом процесса, о котором Вы знаете.

91
27.07.2014, 22:40
5 ответов

Попробуйте:

#!/bin/bash 

_term() { 
  echo "Caught SIGTERM signal!" 
  kill -TERM "$child" 2>/dev/null
}

trap _term SIGTERM

echo "Doing some initial work...";
/bin/start/main/server --nodaemon &

child=$! 
wait "$child"

Обычно, bash игнорирует любые сигналы во время выполнения дочернего процесса. Запустив сервер с помощью &, он запишется в систему управления заданиями оболочки, при этом $! будет держать PID сервера (для использования с wait и kill). Вызов wait будет ждать завершения задания с указанным PID (сервера), или увольнения любых сигналов .

Когда оболочка получает SIGTERM (или сервер выходит независимо), возвратится вызов wait (выход с кодом выхода сервера, или с номером сигнала + 128 в случае получения сигнала). После этого, если оболочка получила ЗАПИСЬ, она вызовет функцию _term, указанную в качестве обработчика ловушки ЗАПИСЬ перед выходом (в которой производится очистка и ручное распространение сигнала на процесс сервера с помощью kill).

.
94
27.01.2020, 19:30

# - символ комментариев. Если вы не хотите, чтобы это было, вам нужно либо избежать его, либо цитировать его.

echo 2 \# 2
echo 2 '#' 2
-121--125574-

Bash не пересылает сигналы, такие как SIGTERM для процессов, на которых он в данный момент ждет. Если вы хотите закончить свой скрипт с помощью , на вашем сервере , ваш сервер (позволяя ему обрабатывать сигналы и что-то еще, как если бы вы начали сервер напрямую), вы должны использовать EXEC , который заменит оболочку с открытым процессом :

#!/bin/bash
echo "Doing some initial work....";
exec /bin/start/main/server --nodaemon

, если вам нужно сохранить оболочку по какой-то причине (т. Е. Вам нужно сделать некоторую очистку после завершения сервера), вы должны использовать комбинацию ловушки , , ждут , а Убить . Смотреть Ответ датчика .

79
27.01.2020, 19:30

Andreas Veithen señala que si no necesita regresar de la llamada (como en el ejemplo del OP )simplemente llamar a través del comando execes suficiente(@Stuart P. Bentley's respuesta). De lo contrario, la respuesta "tradicional"trap 'kill $CHILDPID' TERM(@cuonglm )es un comienzo, pero la llamada waiten realidad regresa después de que se ejecuta el controlador de trampas, lo que aún puede ser antes de que el proceso secundario realmente salga. Por lo tanto, se recomienda una llamada "extra" a wait(@ user1463361's answer).

Si bien esto es una mejora, todavía tiene una condición de carrera, lo que significa que es posible que el proceso nunca salga (a menos que el señalizador vuelva a intentar enviar la señal TERM ). La ventana de vulnerabilidad se encuentra entre el registro del manejador de trampas y el registro del PID del niño.

Lo siguiente elimina esa vulnerabilidad (empaquetada en funciones para su reutilización ).

prep_term()
{
    unset term_child_pid
    unset term_kill_needed
    trap 'handle_term' TERM INT
}

handle_term()
{
    if [ "${term_child_pid}" ]; then
        kill -TERM "${term_child_pid}" 2>/dev/null
    else
        term_kill_needed="yes"
    fi
}

wait_term()
{
    term_child_pid=$!
    if [ "${term_kill_needed}" ]; then
        kill -TERM "${term_child_pid}" 2>/dev/null 
    fi
    wait ${term_child_pid} 2>/dev/null
    trap - TERM INT
    wait ${term_child_pid} 2>/dev/null
}

# EXAMPLE USAGE
prep_term
/bin/something &
wait_term
43
27.01.2020, 19:30

Предоставленное решение не работает для меня, потому что процесс был завершен до фактического завершения команды ожидания. Я обнаружил, что статья http://veithen.github.io/2014/11/16/sigterm-propagation.html, последний фрагмент хорошо работает в моем случае приложения, запущенного в OpenShift с пользовательским исполнителем sh. Сценарий sh необходим, потому что мне нужна возможность получать дампы потоков, что невозможно, если PID процесса Java равен 1.

trap 'kill -TERM $PID' TERM INT
$JAVA_EXECUTABLE $JAVA_ARGS &
PID=$!
wait $PID
trap - TERM INT
wait $PID
EXIT_STATUS=$?
9
27.01.2020, 19:30

Чтобы добавить несколько пунктов к приведенным выше ответам:

  1. Запуск процесса в фоновом режиме с помощью '&' и ожидание его pid, как советует @cuonglm , позволит обработчику выполняться во время работы дочернего процесса, но дочерний процесс потеряет возможность перехватывать любой ввод, так как стандартный ввод будет закрыт, как только дочерний элемент будет отсоединен. Чтобы заставить стандартный ввод оставаться открытым, вы можете добавить бесконечный цикл, который вы передаете дочернему процессу. См. этот пост .

Затем прочитайте ввод в текущей оболочке и запишите его в файл proc дочернего процесса, чтобы он перешел на его стандартный ввод:

(while true; do sleep 10000; done) | /bin/start/main/server --nodaemon &
child_pid=$!
while :
do
    result=$(kill -0 $mypid > /dev/null 2>&1)
    if [ $? -ne 0 ] ; then
        # process is gone
        break
    else
        # read input in the current shell and store it in a variable. The timeout only works with Bash, not with Bourne-Shell. You will need to find a way to read stdin instead and sleep 1 sec between each loop
        read -t 1 input 
        
        # echo the input to the proc file of the runuser process so it goes to its stdin
        echo $input > /proc/$child_pid/fd/0 2>/dev/null 
    fi
done
wait $child_pid

ПРИМЕЧАНИЕ. :Это довольно хорошо работает в Linux, но может потребовать некоторых корректировок для других платформ Unix.

РЕДАКТИРОВАТЬ:более простой способ — дублировать стандартный ввод в дескриптор файла, который затем можно использовать в качестве стандартного ввода для фонового процесса:

exec 3<&0
/bin/start/main/server --nodaemon <&3 &
  1. exec — это второе решение, предложенное @ Стюартом П. Бентли , но иногда вам нужно создать процесс с новым PID, или используемая команда может не дать вам выбора и создать процесс с новый PID или даже новый PGID (, например, для runuser с опцией -l ).

  2. Альтернативой вариантам 1 )и 2 )является отправка сигнала группе процессов, а не указание конкретного PID.

Это можно сделать с помощью kill с минусом (-)перед PID дочернего элемента:

kill -TERM -$child_pid

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

0
06.10.2021, 08:17

Теги

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