
У меня есть скрипт bash, который запускает несколько программ.
#!/bin/sh
python program1.py &
python program2.py &
other programs ... &
lastProgram
Я управляю им как./myscript.sh
Когда я нажимаю Ctrl+, Cчтобы закрыть, lastProgram
он выходит, а все остальные продолжают работать в фоновом режиме. Проблема в том, что другие программы нужно завершить.
Как правильно закрыть все программы, запущенные из скрипта?
решение1
Соберите идентификаторы процессов, завершите фоновые процессы при выходе.
#!/bin/bash
killbg() {
for p in "${pids[@]}" ; do
kill "$p";
done
}
trap killbg EXIT
pids=()
background job 1 &
pids+=($!)
background job 2... &
pids+=($!)
foreground job
Trapping EXIT
запускает функцию при выходе из оболочки, независимо от причины. Вы можете изменить это на trap killbg SIGINT
запуск только на ^C
.
Это не проверяет, завершился ли один из фоновых процессов, прежде чем скрипт попытается их застрелить. Если они это сделают, вы можете получить ошибки или, что еще хуже, застрелить не тот процесс.
Или убейте их по идентификатору задания. Давайте прочитаем вывод, jobs
чтобы узнать, какие из них все еще активны.
#!/bin/bash
killjobs() {
for x in $(jobs | awk -F '[][]' '{print $2}' ) ; do
kill %$x
done
}
trap killjobs EXIT
sleep 999 &
sleep 1 &
sleep 999 &
sleep 30
Если вы запускаете фоновые процессы, которые порождают другие процессы (например, подоболочку: (sleep 1234 ; echo foo) &
), вам нужно включить управление заданиями с помощью set -m
("режим монитора"), чтобы это работало. В противном случае завершается только ведущий процесс.
решение2
Я только что читал похожие вопросы о сборе PID и их последующем уничтожении в конце скрипта -проблемаэто PID для завершенного процесса?можно переработать и повторно использовать в новом процессепрежде чем ваш сценарий закончится, и тогда вы могли быубить новый (случайный) процесс.
Перехватите EXIT и убейте с помощью управления заданиями bash
Вы можете использовать управление заданиями bash, чтобы завершать только процессы, запущенные в скрипте с помощью ловушки и %n jobspec, подсчитывая максимальное количество заданий, которые могут быть запущены (в этом примере только 3):
#!/bin/bash
#trap 'kill %1 %2 %3' 0 # 0 or EXIT are equivalent
#trap 'kill %1 %2 %3' EXIT # or use {1..n} as below
trap 'kill %{1..3}' EXIT
sleep 33 &
sleep 33 &
sleep 33 &
echo processes are running, ctrl-c the next sleep
sleep 66
echo this line will never be executed
Любые дополнительные «завершения» несуществующих спецификаций заданий, которые уже завершены, приведут только к сообщению об ошибке, но не завершат никакие другие новые/случайные процессы.
убить всю группу процессов вашего скрипта
Вот немного другой способ убить всю группу процессов вашего скрипта. Но если управление заданиями вашего скрипта/оболочки не настроено, то этомогунаследовать свой PPID от родителя... но без управления заданиями вышесказанное тоже не будет работать.
Разница в том, что эта команда kill для trap использует PID bash, поскольку он становится PGID для новых процессов:
trap 'kill -- -$$' EXIT
Видетьэтот связанный Qилиздесь Йоханнес «рыба» Цимке ловит SIGINT и SIGTERM и использует их setsid
для «убить всю группу процессов в новой группе процессов, чтобы не рисковать убить себя.")
решение3
Если вы хотите завершить все фоновые процессы, если они не завершатся до lastProgram
окончания выполнения, вам нужно будет сохранить все pid:
python program1.py &
p1pid=$!
python program2.py &
p2pid=$!
other programs ... &
p3pid=$!
lastProgram
kill $p1pid $p2pid $p3pid
Если вы просто хотите дождаться завершения выполнения всех фоновых процессов, прежде чем выйти из скрипта, вы можете использовать команду wait
.
python program1.py &
python program2.py &
other programs ... &
lastProgram
wait
решение4
Вот моя однострочная команда (на bash
):
trap "jobs -p | xargs kill ; trap - INT" INT ; cmd1 & cmd2 & cmd3 &
# replace `cmds` with your command
Он перехватывает Ctrl+ C, чтобы завершить все фоновые задания и вернуться к поведению по умолчанию.
Затем он запускает все команды в фоновом режиме.
Если нажать Ctrl+ C, они все будут убиты, а ловушка вернется к своему поведению по умолчанию.