Ubuntu – Create bash menu based on file list (map files to numbers)

bashcommand linescripts

This answer shows great and intuitive bash menu where you just press number and item is selected. But it's kinda inconvenient for file list, because it's all hardcoded. I'd rather fill my files in some sort of array, then let user pick a number which again maps to array offset.


Basically this is what I imagine:

Following `*.war` archives were found, select one:

  1) old.war
  2) debug.war
  3) release.war

Use number to select a file or 'stop' to cancel: blah
'blah' is not a number
Use number to select a file or 'stop' to cancel: 2
debug.war installed

But how do I turn list of files into this array thingy:

options=("Option 1" "Option 2" "Option 3" "Quit")

How do I get string at certain offset in options? How do I ensure user is asked to try again? Can I allow for string stop to stop selection mode?

Best Answer

To save the outputs of find in a bash array use this:

unset options i
while IFS= read -r -d $'\0' f; do
  options[i++]="$f"
done < <(find /dir/ -maxdepth 1 -type f -name "*.war" -print0 )
  • read reads the input from find null delimited (-d $'\0').
    • The array $options is filled with the filenames.
  • find searches only for files (-type f) within the given directory (-maxdepth 1) with ending .war (-name "*.war") and prints them delimted by the null character (-print0).

The select menu can be done like this:

select opt in "${options[@]}" "Stop the script"; do
  case $opt in
    *.war)
      echo "War file $opt selected"
      # processing
      ;;
    "Stop the script")
      echo "You chose to stop"
      break
      ;;
    *)
      echo "This is not a number"
      ;;
  esac
done

It works as follows:

1) /dir/old.war
2) /dir/debug.war
3) /dir/release.war
4) Stop the script
#? test
This is not a number
#? 2
War file /dir/debug.war selected
#? 4
You chose to stop