6

I'm trying to make a stopwatch, and when user press Q I want to exit.

I found two script, one where a clock is displayed until ctrl + z is pressed. And one script that exit if "q" is pressed.

I've tried to combined them, but "read" seems to mess it all up.

The reason I want to achieve this is that if the user press Q the time elapsed will be saved to a file.

Stopwatch:

BEGIN=$(date +%s)

echo Starting Stopwatch...

while true; do
   NOW=$(date +%s)
   let DIFF=$(($NOW - $BEGIN))
   let MINS=$(($DIFF / 60))
   let SECS=$(($DIFF % 60))
   let HOURS=$(($DIFF / 3600))
   let DAYS=$(($DIFF / 86400))

   # \r  is a "carriage return" - returns cursor to start of line
   printf "\r%3d Days, %02d:%02d:%02d" $DAYS $HOURS $MINS $SECS
   sleep 0.25
done

Exit on q:

while true; do
    echo -en "Press Q to exit \t\t: "
    read input
    if [[ $input = "q" ]] || [[ $input = "Q" ]] 
        then break 
    else 
        echo "Invalid Input."
    fi
done

PS: I'm very new to this.

6

Maybe this helps you. I integrated both of them, with slight modifications though. Here's the result.

BEGIN=$(date +%s)

echo Starting Stopwatch...
echo Press Q to exit.

while true; do
    NOW=$(date +%s)
    let DIFF=$(($NOW - $BEGIN))
    let MINS=$(($DIFF / 60))
    let SECS=$(($DIFF % 60))
    let HOURS=$(($DIFF / 3600))
    let DAYS=$(($DIFF / 86400))

    # \r  is a "carriage return" - returns cursor to start of line
    printf "\r%3d Days, %02d:%02d:%02d" $DAYS $HOURS $MINS $SECS

# In the following line -t for timeout, -N for just 1 character
    read -t 0.25 -N 1 input
    if [[ $input = "q" ]] || [[ $input = "Q" ]]; then
# The following line is for the prompt to appear on a new line.
        echo
        break 
    fi
done

As you can see, I put the second script in place of the sleep command in the former first one. The time-out in read now bears the time lapse function. Notice that the -N option is needed for read not to wait for Enter and react as soon as the first key has been pressed.

  • Worked like a charm! Thank you so much for the explanation. – gel Oct 6 '16 at 22:05
1

Inpired from this answer, you can use read with the -t option, so that it only waits for a specified time, and not indefinitely. The code below combines the two snippets you posted:

#!/bin/bash

begin=$(date +%s)
echo "Starting Stopwatch... Press q to exit"
while true; do
   now=$(date +%s)
   diff=$(($now - $begin))
   mins=$(($diff / 60))
   secs=$(($diff % 60))
   hours=$(($diff / 3600))
   days=$(($diff / 86400))

   # \r  is a "carriage return" - returns cursor to start of line
   # with \33[2K we clear the current line
   printf "\33[2K\r%3d Days, %02d:%02d:%02d" $days $hours $mins $secs

   # -n 1 to get one character at a time, -t 0.1 to set a timeout 
   read -n 1 -t 0.1 input                  # so read doesn't hang
   if [[ $input = "q" ]] || [[ $input = "Q" ]] 
   then
      echo # to get a newline after quitting
      break
   fi
done

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.