Как остановить бесконечный цикл в bash-скрипт корректно?

Мне нужно запускать приложение каждые X секунд, поэтому, поскольку cron не работает с секундами таким образом, я написал сценарий bash с бесконечным циклом, в котором X секунд спит.

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

У вас есть идеи, как этого можно добиться? Я подумал о том, чтобы поспорить, но не смог. найдите, как передать аргумент в running script.

4 ответов


вы можете поймать сигнал, сказать SIGUSR1:

echo "My pid is: $$"
finish=0
trap 'finish=1' SIGUSR1

while (( finish != 1 ))
do
    stuff
    sleep 42
done

затем, когда вы хотите выйти из цикла на следующей итерации:

kill -SIGUSR1 pid

здесь pid - идентификатор процесса скрипта. Если сигнал поднимается во время сна, он проснется (сон спит, пока не появится какой-либо сигнал).


вы можете передать некоторые аргументы файлом. На каждой итерации вы можете прочитать этот файл и посмотреть, изменились ли ваши запущенные условия.


следующая структура может быть подходящей, если вам все равно нужно выполнить некоторую очистку. Используйте kill, как показано в ответе cdarke.

#===============================================================
#  FUNCTION DEFINITIONS
#===============================================================
# . . .

#===  FUNCTION  ================================================
#          NAME:  cleanup
#   DESCRIPTION:  
#===============================================================
cleanup ()
{
  # wait for active children, remove empty logfile, ..., exit
  exit 0
} # ----------  end of function cleanup  ----------

#===============================================================
#   TRAPS
#===============================================================
trap  cleanup SIGUSR1

#===============================================================
#   MAIN SCRIPT
#===============================================================
echo -e "Script '' / PID ${$}"

while : ; do                                # infinite loop
  # . . .
  sleep 10
done
# . . .

#===============================================================
#   STATISTICS / CLEANUP
#===============================================================
cleanup

решение trap, опубликованное ранее, хорошо для больших циклов, но громоздко для общего случая, когда вы просто зацикливаетесь на одной или нескольких командах. В этом случае я рекомендую следующее решение:

while whatever; do
    command || break
done

это выйдет из цикла, если команда имеет ненулевой код выхода, что произойдет, если он будет прерван. Так что, если command ручки SIGINT, нажатие ctrl-C остановит текущую команду и выйдет из цикла.

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