Reputation: 2866
I have an array which I am using to generate a list which a user can choose from made like this.
list=(a b c d)
n=0
for x in ${list[@]}
do echo $n\)$x
n=$((n++)
done
read -p "Pick an item:" choice
I want to allow only valid options to be chosen so I am checking like this.
if [[ $choice -gt ${#list[@]} && $choice -lt -1 ]]
then ...
else
echo "not a valid choice"
The issue I am having is all strings evaluate at equal to zero. ie [[ "I am a duck" -eq 0 ]]
is True, as is (( "I am a duck" == 0 ))
. Is there a way to make all string and number comparison evaluate to false? I know I can check for a string with [[ $choice =~ [A-Za-z]+ ]]
, but I am wondering if there is a way without regular expressions?
EDIT Sorry, I should have tested the "I am a duck" statement before I put it down. It doesn't like the spaces. However, "I_am_a_duck" does evaluate to 0. This explained by chepner below.
Upvotes: 0
Views: 70
Reputation: 52371
I would use select
for this and not deal with behaviour of strings in arithmetic contexts (as explained in chepner's answer) at all:
list=(a b c d)
PS3='Pick an item: '
select opt in "${list[@]}"; do
case $opt in
[abcd]) echo "Choice: $opt ($REPLY)" ;;
*) echo "Illegal choice" ;;
esac
done
This will keep looping; to continue after a valid selection, there has to be a break
somewhere. The main benefit is select
taking care of invalid inputs for you, and you don't have to build the menu yourself.
Upvotes: 1
Reputation: 531908
-gt
, because it is intended to compare integers, triggers the same behavior for strings as seen in an arithmetic expression: the string is treated as the name of a parameter, and that parameter is expanded (repeat the process if necessary) until you get an integer. If there is no parameter by that name, 0 is substituted.
That said, you could weasel your way out of the problem by number your items starting at one and using
if (( choice < 1 || choice > ${#list[@]} )); then
echo "not a valid choice"
since now any non-integer inputs will be treated as 0, which is indeed less than the lower limit of 1.
Upvotes: 2