Search code examples
bashloopssleep

Bash skip sleep and go to next loop iteration


I have a bash loop that looks like this:

something(){
    echo "something"
}

while true; do
    something
    sleep 10s
done | otherCommand

When the loop is in the sleep state, I want to be able to be able to run a function from the terminal that will skip the sleep step and go on to the next iteration of the loop.

For example, if the script has been sleeping for 5 seconds, I want the command to stop the script from sleeping, go on to the next iteration of the loop, run something, and continue sleeping again.


Solution

  • This is not foolproof, but may be robust enough:

    To interrupt the sleep command, run:

    pkill -f 'sleep 10s'
    

    Note that the script running the sleep command prints something like the following to stderr when sleep is killed: <script-path>: line <line-number>: <pid> Terminated: 15 sleep 10s. Curiously, you cannot suppress this script with sleep 10s 2>/dev/null; to suppress it, you have to either apply 2>/dev/null to the while loop as a whole, or to the script invocation as a whole.

    As @miken32 points out in the comments, this command tries to kill all commands whose invocation command line matches sleep 10s, though - unless you're running as root - killing will only succeed for matches among your processed due to lack of permission to kill other users' processes.

    To be safer, you can explicitly restrict matches to your own processes:

    pkill -u "$(id -u)" -f 'sleep 10s'
    

    Truly safe use, however, requires that you capture your running script's PID (process ID), save it to a file, and use the PID from that file with pkill's -P option, which limits matches to child processes of the specified PID - see this answer (thanks, @miken32).