简体   繁体   中英

Linux Read - Timeout after x seconds *idle*

I have a (bash) script on a server that I have inherited the administration aspect of, and have recently discovered a flaw in the script that nobody has brought to my attention.

After discovering the issue, others have told me that it has been irritating them, but never told me (great...)

So, the script follows this concept

#!/bin/bash
function refreshscreen(){
  # This function refreshes a "statistics screen"
  ...
  echo "Enter command to override update"
  read -t 10 variable
}

This script refreshes a statistics screen, and allows the user to stall the update in lieu of commands built into a case statement. However, the read times-out ( read -t 10 ) after 10 seconds, regardless of if the user is typing.

Long story short, is there a way to prevent read from timing out if the user is actively typing a command? Best case scenario would be a "Time out of SEC idle/inactive seconds" opposed to just timeout after x seconds.

I have thought about running a background script at the end of the cycle before the read command pauses the screen to check for inactivity, but have not found a way to make that command work.

You can use read in a loop, reading one character at a time, and adding it to a final read string. This would then give the user some timeout amount of time per character rather than per command. Here's a sample function you might be able to incorporate into your script that shows what I'm talking about:

read_with_idle_timeout() {
    local input=""

    read -t 10 -N 1 variable

    while [ ! -z $variable ]
    do
        input+=$variable
        read -t 10 -N 1 variable
    done

    echo "Read: $input"
}

This will give the user 10 seconds to type each character. If they stop typing, you'll get as much of the command as they had started typing before the timeout occurred, and then your case statement can handle it. Perhaps you can store the final string in a global variable, or just put this code directly into your other function.

If you need more than one word, since read breaks on $IFS , you could call this function multiple times until you get all the input you're expecting.

I have searched for a simple solution that will do the following:

  • timeout after 10 seconds, if there is no user input at all
  • the user has infinite time to finish his answer if the first character was typed within the first 10 sec.

This can be implemented in two lines as follows:

read -N 1 -t 10 -p "What is your name? > " a
[ "$a" != "" ] && read b && echo "Your name is $a$b" || echo "(timeout)"

In case the user waits 10 sec before he enters the first character, the output will be:

What is your name? > (timeout)

If the user types the first character within 10 sec, he has unlimited time to finish this task. The output will look like follows:

What is your name? > Oliver
Your name is Oliver

Caveat: the first character is not editable, once it was typed, while all other characters can be edited (backspace and re-type). Any ideas for a simple solution?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM