0

In the shell, I would like to ask the user to choose between one of two options, then when either the 1 or 2, do a switch statement with it. How can I go about doing this.

echo "Press [1] to transfer to $drive1"
echo "Press [2] to transfer to $drive2"

read #input somehow?

I've tried making the second echo into a read. But ideally I'd like to put the two echos into a here document, then apply that to a read but I could not get the lines correct.

options <<_EOF_

"Press [1] to transfer to $drive1"
"Press [2] to transfer to $drive2"

_EOF_
read $options -n 1

But I get the error line 7: options: command not found

1252748
  • 14,597
  • 32
  • 109
  • 229
  • 2
    possible duplicate of [How to assign a heredoc value to a variable in Bash?](http://stackoverflow.com/questions/1167746/how-to-assign-a-heredoc-value-to-a-variable-in-bash) – Etan Reisner Mar 04 '15 at 20:27
  • @EtanReisner I am looking at that page, but it seems much more complex than my question. Is there a simpler way than the selected answer's use of `read`? – 1252748 Mar 04 '15 at 20:32
  • What about `select drive in "${drives[@]}"; do case …; esac; done`? – kojiro Mar 04 '15 at 20:34
  • Not very nice and requires a cat: `options=$( cat < – tgo Mar 04 '15 at 20:37
  • Another solution would be writing the menu in a cfg file: http://unix.stackexchange.com/questions/38200/ksh-styling-text-based-menu-using-stderr/115371#115371 – Walter A Mar 04 '15 at 21:15

2 Answers2

2

You want to do two things:

  1. Write a message to the user
  2. Read a number

These are two entirely separate operations, and you shouldn't try to combine them. To write out a message in a here doc, use cat:

cat << EOF
Press [1] to transfer to $drive1
Press [2] to transfer to $drive2

EOF

To read a number:

read -n 1 option

Here all together:

#!/bin/bash
cat << EOF
Press [1] to transfer to $drive1
Press [2] to transfer to $drive2

EOF

read -n 1 option

echo
echo "You entered: $option"
Jounathaen
  • 803
  • 1
  • 9
  • 23
that other guy
  • 116,971
  • 11
  • 170
  • 194
  • 1
    Thanks for the help. If anyone sees this in the future, be advised that copy/pasting from SO is going to get you a lot of whitespace after the `EOF`s, which will break the heredoc so you'll have to delete it. Thanks again man. – 1252748 Mar 04 '15 at 20:42
  • @1252748 I removed the whitespaces, peer review pending... This is not always the case, but happened this time – Jounathaen Sep 14 '17 at 08:24
2

You could do

cat << PROMPT
Press [1] to transfer to $drive1
Press [2] to transfer to $drive2
PROMPT
read -n1 drivenumber
case "$drivenumber" in
    1) handle drive 1;;
    2) handle drive 2;;
    *) handle invalid input;;
esac

That would suit your stated requirements. But you have to do extra work to avoid invalid inputs:

input=
while true; do
    that whole thing
    validate_input && break
    echo "oh no your input was invalid"
done

Further, to clarify my select comment above, the architecture implied by using a heredoc is a little cumbersome when you want to change the number of drives.

drives=( "$drive1" "$drive2" )
PS3="Choose a drive to transfer to"
select drive in "${drives[@]}"; do
    # really no need for a case statement anymore
    do_x_to "$drive"
done

Or you could take the hybrid road:

while true; do
    for i in "${!drives[@]}"; do
        printf 'Press [%d] to transfer to %s\n' "$i" "${drives[i]}"
    done
    read -n1 drive_number
    if [[ ! ${drives[drive_number]} ]]; then
        echo "invalid drive number" >&2
        continue
    fi
    drive=${drives[drive_number]}
    case "$drive" in …
    esac
done
kojiro
  • 74,557
  • 19
  • 143
  • 201