Bash запускает несколько программ и обрабатывает close

В основном у вас есть три варианта:

  1. export -f (это функция, не относящаяся к POSIX bash )
  2. Выполнение оболочки, определяющей функцию при каждом вызове
  3. Переместите функцию в сценарий оболочки и запустите его вместо этого

Вариант 1, вероятно, проще всего продемонстрировать, поэтому я покажу его:

$ f() { num=$1; echo "$num is an integer"; }
$ export -f f
$ cat Commands.txt 
number=1; f "$number" 
number=2; f "$number" 
number=3; f "$number" 
number=4; f "$number" 
number=5; f "$number" 
$ parallel :::: Commands.txt
1 is an integer
2 is an integer
3 is an integer
4 is an integer
5 is an integer

Обратите внимание, что ваша популяция Commands.txt , скорее всего, ошибочна, вам нужно f "$ number" в Commands.txt , чтобы передать номер, а не ] f число , которое передало бы буквальную строку «число». Ваш скрипт для его генерации должен выполнять echo "number = $ i; f \" \ $ number \ "" (обратите внимание на escape-символы, которые важны, чтобы избежать интерпретации $ number в echo время или " с завершающей строки).

4
28.04.2017, 18:11
4 ответа

Соберите идентификаторы процессов, завершите фоновые процессы при выходе.

#!/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

Перехват 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 ( «режим монитора»), чтобы это работало. В противном случае завершается только ведущий процесс.

4
27.01.2020, 20:49

Если вы хотите завершить все фоновые процессы, если они не завершились до завершения выполнения lastProgram, вам необходимо сохранить все pids:

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
1
27.01.2020, 20:49

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

Перехват EXIT и уничтожение с помощью управления заданиями bash.

Вы можете использовать управление заданиями bash, чтобы завершать только процессы, запущенные в сценарии, с помощью прерывания и задания %n, подсчитывая максимальное количество заданий, которые могут быть запущены (только 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 или здесь, где Йоханнес 'fish' Ziemke ловит SIGINT и SIGTERM и использует setsid для «уничтожения всей группы процессов в новой группе процессов, чтобы мы не рисковали убить самих себя)

3
27.01.2020, 20:49

Вот моя однострочная команда (вbash):

trap "jobs -p | xargs kill ; trap - INT" INT ; cmd1 & cmd2 & cmd3 &
# replace `cmds` with your command

Он перехватывает Ctrl + C , чтобы закрыть все фоновые задания и вернуться к поведению по умолчанию.

Затем все команды выполняются в фоновом режиме.

При нажатии Ctrl + C ,он убьет их всех и вернет ловушку к ее поведению по умолчанию.

1
30.06.2020, 09:44

Теги

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