1

Consider the following bash code:

echo -e "\nThe following versions are available for install:"
declare -A VERS
CNT=0
for FILE in `ls ${ASSET_DIR}/enterprise`; do
  let "CNT++"
  VERS_STR=`sed -e 's/^file-\([0-9].[0-9].[0-9]\).zip/\1/' <<< ${FILE}`
  VERS[${CNT}]=${VER_STR}
done
for i in ${!VERS[@]}; do
  echo "  ${i} - ${VERS[${i}]}"
done
echo -n "Which version do you want to install?: "
read VERS_INPUT

$VERS_INPUT should equate to one of the keys in the associative array $VERS. How can I verify that the value of $VERS_INPUT equals any of the keys of $VERS. As it stands right now, with our current setup, there's 6 available options generated from the for loop(s), but this has potential to grow, thus I don't want to make it a static check and have to change the script every time an additional file gets put in ${ASSET_DIR}/enterprise. I presume an if statement is in order, but I'm not certain how I would check that it matches a key from the associative array.


EDIT:

To give an example, lets say the first for loop dynamically generated the associative array $VERS with four values:

$ echo $ENV["1"]
3.4.3

$ echo $ENV["2"]
3.4.4

$ echo $ENV["3"]
3.4.5

$ echo $ENV["4"]
3.4.6

The user is prompted to enter a value (assigned to variable $VERS_INPUT) that should hopefully be 1, 2, 3, or 4. How can I check that the value of $VERS_INPUT is either 1, 2, 3, or 4. Obviously this is an arbitrary example, since my list is currently at 6 available options, and is only going to grow further. I want to make this as dynamic as possible, since 1, 2, 3, 4, etc... is dynamically generated from the first for loop and is not manually generated.

1
  • Don't parse the output of ls if you can avoid it. Whitespace is our enemy. Whitespace in filenames is a massive enemy. for FILE in ${ASSET_DIR}/enterprise/*; do should do it. Take care on hidden files. Commented Feb 29, 2012 at 21:45

1 Answer 1

1

I hope I understood your question: Matching a user input to an index of an array of unknown length. This testcode works:

#!/bin/bash
VERS=(1.1.1 1.1.2 1.2.1 1.2.2 1.3.1 terminate)

select val in ${VERS[*]}
do
    case $val in 
      terminate)
        echo "... done"
        break
        ;;
      [0-9]*) 
        echo "match " $val
        ;;
      *) 
        echo "fail (empty:)" $val
        ;;
    esac    
done

interactive output:

./version.sh 
1) 1.1.1      3) 1.2.1      5) 1.3.1
2) 1.1.2      4) 1.2.2      6) terminate
#? 0
fail (empty:)
#? 1
match  1.1.1
#? 6
... done

If the user inputs 1 to 5, the associated array element is printed.

Input is terminated with 6.

It's not exactly what you asked for, but it's a shell buildin, and maybe usable for you help select prints the chapter of the manpage.

Sign up to request clarification or add additional context in comments.

5 Comments

Not quite. I edited the original question with further clarification using an arbitrary example. The array is dynamically generated, and I want to compare the string against the keys in the array, not the value associated with those keys.
So if I'm not mistaken, it would appear that between the do and done I could incorporate a further check to ensure the string isn't empty and that it matches the 3 digit pattern with a bash if statement? Am I correct in thinking that would be a feasible solution?
Yes. If it is empty, the number didn't match. You needn't repeat the selection and may break after the first positive match, if you like to restrict the action to one version. You can't select multiple selections at once (1 3 4) with this approach. You can add a termination case to the array, to have a more convenient way to terminate the selection than ^d.
Just tried it out. Unfortunately it's not what I'm looking for. I originally thought this was some form of a shorthand case-like function. Being that there's multiple other reads going on, this one stands out and is a little too non-intuitive on the user end to use. Thanks for the suggestion though.
You don't need multiple reads - only the simplest implementation does so, but if you like, you may break always: for invalid input, as well as for valid one. In the actualized example, I put a break case into the explicit termination case, but you can have one in the matching case too, and you don't need an explicit "terminate", nor to handle mismatches. How would you like the dialog to happen?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.