How to stop infinite loop in bash script gracefully?
Solution 1
You could trap a signal, say SIGUSR1:
echo "My pid is: $$"
finish=0
trap 'finish=1' SIGUSR1
while (( finish != 1 ))
do
stuff
sleep 42
done
Then, when you want to exit the loop at the next iteration:
kill -SIGUSR1 pid
Where pid
is the process-id of the script. If the signal is raised during the sleep, it will wake (sleep sleeps until any signal occurs).
Solution 2
You may pass some arguments by a file. On each iteration you may read this file and see if your running condtions got changed.
Solution 3
The following structure may be appropriate if you have to do some cleanup anyway. Use kill as shown in cdarke's answer.
#===============================================================
# 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 '$0' / PID ${$}"
while : ; do # infinite loop
# . . .
sleep 10
done
# . . .
#===============================================================
# STATISTICS / CLEANUP
#===============================================================
cleanup
Solution 4
The trap solution posted earlier is good for large loops, but cumbersome for the common case where you are just looping over a single or a few commands. In this case I recommend the following solution:
while whatever; do
command || break
done
This will exit the loop if command has a non-zero exit code, which will happen if it is interrupted. So unless command
handles SIGINT
, pressing ctrl-C will both stop the current command and exit the loop.
Edit: After reading your question more closely, I see that you want the current command to continue executing. In that case this solution does not apply.
Samurai Girl
Updated on July 27, 2022Comments
-
Samurai Girl almost 2 years
I need to run application in every X seconds, so, as far as cron does not work with seconds this way, I wrote a bash script with infinite loop having X seconds sleep in it.
When I have to stop the running script manually, I would like to do it in a correct way - let the application complete functioning and just do not enter the loop for the next time.
Do you have any idea, how this can be achieved? I thought about passing arguments, but I could not find how to pass argument to running script.