4

I have a bash script that

  • has a for loop that iterates a lot of times and sleeps between iterations, potentially for a long time. It then

  • writes results to a file, then terminates.

On occasion I get the result I need before many loop iterations are complete.

On these occasions I need the script to break out of the for loop while it is either

  • doing stuff, or

  • sleeping

in such as way that it will continue with the rest of the script, after the for loop, which is writing a report file of data it's gathered so far.

I wish to use a key combination, eg CTRL+Q, to break out of the for loop.

Script looks like this:

#!/bin/bash

for (( c=0; c<=$1; c++ ))
do  

# SOME STUFF HERE
#  data gathering into arrays and other commands here etc

# sleep potentially for a long time
sleep $2

done

#WRITE REPORT OUT TO SCREEN AND FILE HERE
6

I've not had contact with this kind of tasks for a while, but I remember something like this used to work:

#!/bin/bash

trap break INT

for (( c=0; c<=$1; c++ ))
do  

# SOME STUFF HERE
#  data gathering into arrays and other commands here etc

    echo loop "$c" before sleep

    # sleep potentially for a long time
    sleep "$2"

    echo loop "$c" after sleep

done

#WRITE REPORT OUT TO SCREEN AND FILE HERE

echo outside

The idea is to use Ctrl-C to break the loop. This signal (SIGINT) is caught by the trap, which breaks the loop and lets the rest of the script follow.

Example:

$ ./s 3 1
loop 0 before sleep
loop 0 after sleep
loop 1 before sleep
^Coutside

Let me know if you have any problems with this.

5

The easiest way is to use Ctrl+C, since by default it gives the INT signal, which causes most applications to stop, and you can catch it in the shell.

To interrupt the whole loop at once, you could run it in a subshell, and exit when interrupted. Here, the trap is set only in the subshell, and only it exits.

#!/bin/bash

(
trap "echo interrupted.; exit 0" INT
while true; do
        echo "running some task..."
        some heavy task 
        echo "running sleep..."
        sleep 5;
        echo "iteration end."
done
)

echo "script end."
  • 1
    @Kes, hmmh, I tested that on Debian with Bash 4.4. and Bash 5, and I'm not sure what would cause the difference. But if Tomasz's break solution works, then use that! – ilkkachu Jan 26 at 14:32
  • Thanks @ilkkachu for your solution. It does work. It was my mistake. I forgot to use the shift to get the upper case C. – Kes Jan 26 at 14:34
2

In some cases it is better to have a solution that does not interrupt "SOME STUFF HERE", and only breaks while the shellscript is waiting.

Then you can use the shell built-in command read with some options instead of sleep.

Try this shellscript,

#!/bin/bash

echo "Press 'q' to quit the loop and write the report"
echo "Press 'Enter' to hurry up (skip waiting this time)"

for (( c=0; c<=$1; c++ ))
do  

 echo "SOME STUFF HERE (pretending to work for 5 seconds) ..."
 sleep 5
 echo "Done some stuff"

#  data gathering into arrays and other commands here etc

# sleep potentially for a long time

#sleep $2
 read -n1 -st$2 ans
 if [ "$ans" == "q" ]
 then
  break
 elif [ "$ans" != "" ]
 then
  read -n1 -st$2 ans
 fi
done

echo "WRITE REPORT OUT TO SCREEN AND FILE HERE"

You find details about read with the command help read,

      -n nchars return after reading NCHARS characters rather than waiting
            for a newline, but honor a delimiter if fewer than
            NCHARS characters are read before the delimiter
      -s    do not echo input coming from a terminal
      -t timeout    time out and return failure if a complete line of
            input is not read within TIMEOUT seconds.  The value of the
            TMOUT variable is the default timeout.  TIMEOUT may be a
            fractional number.  If TIMEOUT is 0, read returns
            immediately, without trying to read any data, returning
            success only if input is available on the specified
            file descriptor.  The exit status is greater than 128
            if the timeout is exceeded

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.