bashtimeout

Bash Read -t but in milliseconds?


Hi in my code I have while loop and at the beginning of that while loop, I use the read function to make kill function. So every time the program goes through the loop it will first check if you pressed the kill button.

Problem is, is that the read command timeout cannot be shorter than 1 second. This makes the program annoyingly slow.

Is there a way to time out the read command in milliseconds? or should I work with something else to kill the program?

while(true)

do
 read -n1 -t 0.01 killer
 if [ "$killer" == "k" ]
 then
   echo "ill!!!"
   pkill -9 -e -f gnome-terminal- # a ros node that's running in the background
   pkill -9 -e -f Test_PI.sh # the name of the bash
 fi

 echo "working"
 clear
done

Solution

  • According to the Bash Changelog, bash-4.0-alpha introduced fractional timeouts:

    y. The -t option to the read builtin now supports fractional timeout values.

    Source: Bash Changelog

    This can be tested easily with:

    $ time read -t 0.4
    real    0m0.400s
    user    0m0.000s
    sys     0m0.000s
    

    Using this, you can alter your script as:

    while :; do
      if read -n1 -t 0.01 key; then
         if [[ "$key" == "k" ]]; then
            ...
         fi
      fi
    done
    

    Or if you make use of the zero timeouts, you can do

    while :; do
      if read -t 0 && read -n1 key; then
         if [[ "$key" == "k" ]]; then
            ...
         fi
      fi
    done
      
    

    -t timeout :: Cause read to time out and return failure if a complete line of input is not read within timeout seconds. timeout may be a decimal number with a fractional portion following the decimal point. This option is only effective if read is reading input from a terminal, pipe, or other special files; it has no effect when reading from regular files. If timeout is 0, read returns success if input is available on the specified file descriptor, failure otherwise. The exit status is greater than 128 if the timeout is exceeded.

    Source: man bash, section read