Bash read input in case statement not working as expected

I'm having an issue with bash read input when using a case statement.

The script halts and doesn't read the input on the first loop. if I hit enter then the scripts starts to respond as expected. Need some help here.

defaultans=8hrs
read -e -i $defaultans -p "${bldwht}How long would you like to grant access to $USERNAME (8hrs,24hrs,48hrs,72hrs,96hrs,1wk or 2wk)? ${txtrst}" input
defaultans="${input:-$defaultans}"
#echo -e "${bldwht}How long would you like to grant access to $USERNAME (8hrs,24hrs,48hrs,72hrs,96hrs,1wk or 2wk)? ${txtrst}"
       echo "       "
        echo "       "
while true; do
read defaultans
case $defaultans in
     8hrs ) break;;
     24hrs ) break;;
     48hrs ) break;;
     72hrs ) break;;
     96hrs ) break;;
       1wk ) break;;
       2wk ) break;;
     * ) echo "You entered an invalid choice. You must choose 8hrs,24hrs,48hrs,72hrs,96hrs,1wk or 2wk access.";;
    esac
done

Script output in debug.

+ defaultans=8hrs
+ read -e -i 8hrs -p 'How long would you like to grant access to tnew (8hrs,24hrs,48hrs,72hrs,96hrs,1wk or 2wk)? ' input
How long would you like to grant access to tnew (8hrs,24hrs,48hrs,72hrs,96hrs,1wk or 2wk)? 8hrs
+ defaultans=8hrs
+ echo '       '

+ echo '       '

+ true
+ read defaultans  < script sits here and doesn't read the given defaultans above.


##Once I hit enter one time the script proceeds as expected.
+ case $defaultans in
+ echo 'You entered an invalid choice. You must choose 8hrs,24hrs,48hrs,72hrs,96hrs,1wk or 2wk access.'
You entered an invalid choice. You must choose 8hrs,24hrs,48hrs,72hrs,96hrs,1wk or 2wk access.
+ true
+ read defaultans

You have a read command at the start of your script and you have a read command inside your loop. Every read command will wait for you to type in a response.

Try replacing the first read with an echo or printf that gives the directions for the data to be entered and let the read command inside the loop be the only command that blocks waiting for data to be entered.

There is just one loop, and it looks like the first read (outside the loop) has completed accepting the preset value "8hrs" as <return> was hit.

Which is the correct behaviour of read - read a line terminated by a return character.

There are no modifiers / options for this (second) read - no default value, no timeout value, no char count - so, yes, it sits there and waits for your input, terminated by a <Return>.

Here you can avoid repeated instructions by putting them between while and do

while
    defaultans=8hrs
    read -e -i $defaultans -p "${bldwht}How long would you like to grant access to $USERNAME (8hrs,24hrs,48hrs,72hrs,96hrs,1wk,2wk or q)? ${txtrst}" input
    defaultans="${input:-$defaultans}"
    echo "       "
    echo "       "
    echo "$defaultans"
    true
do
    case $defaultans in
    8hrs ) break;;
    24hrs ) break;;
    48hrs ) break;;
    72hrs ) break;;
    96hrs ) break;;
      1wk ) break;;
      2wk ) break;;
    q ) exit;;
    * ) echo "You entered an invalid choice.";;
    esac
done

The last command "true" sets a good exit status (0) so the while loop runs forever, only terminating by the break statements.

Scratching my head - is it wise to modify the default answer instead of working with the input read?

Bash has a built-in menu command called select . Consider this code snippet:

words=(8hrs 24hrs 48hrs 72hrs 96hrs 1wk 2wk)
PS3="Enter a number or q to quit "
printf "How long would you like to grant access to %s?\n" "$USERNAME"
select time in "${words[@]}"
do
   [[ "$REPLY" == [qQ]* ]] && break
   case "${time:-null}" in
      8hrs) break ;;
      24hrs) break ;;
      48hrs) break ;;
      72hrs) break ;;
      96hrs) break ;;
      1wk) break ;;
      2wk) break ;;
      null)
         printf "incorrect answer. Please enter a number 1-%d\n" ${#words[@]}
         ;;
   esac
done
 

The major difference between this and your version is no default value. You could add one by putting this line before the case statement:

   [[ -z "$REPLY" ]] && time=8hrs

Andrew