1

I want to make my script wait for n seconds, during which user can abort the script. My code till now looks like this

echo "Start Date provided :" $STARTDATE
echo "End date provided :" $ENDDATE
echo ""
echo "Please check the dates provided and in case of error press CTRL+C"
seq 1 15 |while read i; do echo -ne "\rWaiting for $i seconds"; sleep 1; done
echo ""
echo "Executing query on the remote side, please wait..."

When the user presses ctrl+c though what happens is that the while loop ends and continues executing the rest of the script.

How can I make it abort the entire script? Thanks in advance for any advise

  • One way would be to register a signal handler for SIGINT. I don't know if that's overly complicated though. – keyser May 09 '14 at 22:17
  • 1
    Why the while loop? Just `sleep` for x seconds. Once you hit CTRL+C, the script will terminate. – Engineer2021 May 09 '14 at 22:34
  • 1
    This is [BashFAQ #68](http://mywiki.wooledge.org/BashFAQ/068), and a very, very commonly asked question on this site (apparently by virtue of folks not checking the FAQ). – Charles Duffy May 09 '14 at 22:45
  • You should accept correct answer with green tick mark and remember you can vote-up more good answers as well. – pawel7318 May 10 '14 at 08:09

3 Answers3

1

I would use trap

#!/bin/bash
trap 'echo -e "\nBye"; exit 1' INT

echo "Please check the dates provided and in case of error press CTRL+C"
seq 1 15 |while read i; do echo -ne "\rWaiting for $i seconds"; sleep 1; done
echo "Executing query on the remote side, please wait..."
0

To catch CTRL+C you can use trap. For example:

#!/bin/bash
trap 'got_one' 2

got_one() {
 echo "I got one"
 exit 69
}

echo -e "PID: $$, PPID: $PPID" 
sleep 100

So your script can look like this:

#!/bin/bash
trap "interrupt" SIGINT

interrupt() {
  echo -e "\nExecution canceled."
  exit 69
}

countdown() {
  duration=$1 # in seconds
  seq $duration -1 0|while read i; do echo -ne "\rWaiting for $i seconds"; sleep 1; done
}

STARTDATE="foo"
ENDDATE="bar"

cat <<END
Start Date provided: $STARTDATE
  End date provided: $ENDDATE

Please check the dates provided and in case of error press CTRL+C
END

countdown 15

echo -e "\nExecuting query on the remote side, please wait..."
pawel7318
  • 3,383
  • 2
  • 28
  • 44
  • 1
    as for functions parameters you can use `$1` without assigning it to another variable however I find it a good habit to name them which makes it clear for future reading – pawel7318 May 10 '14 at 08:12
0

Here's a simpler program that reproduces your problem:

true | sleep 10  # Hit Ctrl-C here
echo "why does this execute?" 

The problem is that bash determines whether or not to continue the script based on whether the SIGINT was handled. It determines whether the SIGINT was handled based on whether or not the process it's currently running is killed by this signal.

Since seq prints its numbers and exits immediately and successfully, it's not killed by SIGINT. bash therefore incorrectly assumes the signal was handled, and it keeps going.

You can solve this in two ways:

  1. Add a SIGINT handler that exits your script regardless of whether the signal appears to be handled.
  2. Don't use seq or anything else that immediately exits.

For the first approach, see user3620917's answer.

The second approach,

for i in {15..1}
do 
  printf '\rYou have %d seconds to hit Ctrl-C' "$i"
  sleep 1
done
Community
  • 1
  • 1
that other guy
  • 116,971
  • 11
  • 170
  • 194