изменить
Для будущих читателей. Корень этой проблемы действительно сводился к запуску функции в интерактивной оболочке, а не к размещению ее в отдельном скрипте.
Кроме того, есть много вещей, которые можно было бы улучшить в коде, который я изначально опубликовал. Пожалуйста, смотрите комментарии для вещей, которые можно было/должно было сделать лучше.
/изменить
У меня есть функция bash, предназначенная для повторного запуска процесса в фоновом режиме при изменении файлов в каталоге (подумайте, как Grunt, но для общих целей). Сценарий работает по желанию во время работы:
- Подпроцесс правильно запущен (включая любые дочерние процессы)
- При смене файла саб убивается (включая детей) и запускается заново
Однако при выходе (ctrl-c) ни один из процессов не уничтожается. Кроме того, нажатие Ctrl-C второй раз завершит текущий сеанс терминала. Я предполагаю, что это проблема с моей ловушкой, но не смог определить причину проблемы.
Вот код rerun.sh
#!/bin/bash
# rerun.sh
_kill_children() {
isTop=$1
curPid=$2
# Get pids of children
children=`ps -o pid --no-headers --ppid ${curPid}`
for child in $children
do
# Call this function to get grandchildren as well
_kill_children 0 $child
done
# Parent calls this with 1, all other with 0 so only children are killed
if [[ $isTop -eq 0 ]]; then
kill -9 $curPid 2> /dev/null
fi
}
rerun() {
trap " _kill_children 1 $$; exit 0" SIGINT SIGTERM
FORMAT=$(echo -e "\033[1;33m%w%f\033[0m written")
#Command that should be repeatedly run is passed as args
args=$@
$args &
#When a file changes in the directory, rerun the process
while inotifywait -qre close_write --format "$FORMAT" .
do
#Kill current bg proc and it's children
_kill_children 1 $$
$args & #Rerun the proc
done
}
#This is sourced in my bash profile so I can run it any time
Чтобы проверить это, создайте пару исполняемых файлов parent.sh и child.sh следующим образом:
#!/bin/bash
#parent.sh
./child.sh
#!/bin/bash
#child.sh
sleep 86400
Затем создайте файл rerun.sh и запустите rerun ./parent.sh
. В другом окне терминала я watch "ps -ef | grep pts/4"
вижу все процессы для повторного запуска (в данном примере на pts/4). Прикосновение к файлу в каталоге вызывает перезапуск parent.sh и дочерних элементов. [ctrl-c] завершает работу, но оставляет запущенными pids. [ctrl-c] снова убивает bash и все остальные процессы на pts/4.
Желаемое поведение: на [ctrl-c] убить детей и нормально выйти в оболочку. Помощь?
-- Источники кода:
Идея Innotify из: https://exyr.org/2011/inotify-run/
Убить детей из: http://riccomini.name/posts/linux/2012-09-25-kill-subprocesses-linux-bash/
args=$@
, например, ошибочно на первый взгляд —$@
— это массив,args
— это скаляр. Вы не можете надежно поместить массив в скаляр, и когда вы запустите$args
позже, вы столкнетесь со всеми ловушками в mywiki.wooledge.org/BashFAQ/050. - person Charles Duffy   schedule 20.07.2015fuser -k
вместо того, чтобы пытаться анализироватьps
. - person Charles Duffy   schedule 20.07.2015echo -e
является злом - например, bash нарушает спецификацию POSIX (не расширяет, нарушает - POSIX-совместимое эхо будет печатать-e
на своем выходе при передаче-e
в своей командной строке), включая его; см. pubs.opengroup.org/onlinepubs/009604599/utilities/echo.html а>.printf
— лучшая альтернатива. - person Charles Duffy   schedule 20.07.2015