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

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

You could also use a shell glob to get the list of files. This approach has the advantage of not using an external program (find) and of not needing any restriction on the type of file (*war, for example) given:

#!/usr/bin/env bash

## Collect the files in the array $files
files=( ~/foo/war/* )
## Enable extended globbing. This lets us use @(foo|bar) to
## match either 'foo' or 'bar'.
shopt -s extglob

## Start building the string to match against.
string="@(${files[0]}"
## Add the rest of the files to the string
for((i=1;i<${#files[@]};i++))
do
    string+="|${files[$i]}"
done
## Close the parenthesis. $string is now @(file1|file2|...|fileN)
string+=")"

## Show the menu. This will list all files and the string "quit"
select file in "${files[@]}" "quit"
do
    case $file in
    ## If the choice is one of the files (if it matches $string)
    $string)
        ## Do something here
        echo "$file"
        ## Uncomment this line if you don't want the menu to
        ## be shown again
        # break;
        ;;

    "quit")
        ## Exit
        exit;;
    *)
        file=""
        echo "Please choose a number from 1 to $((${#files[@]}+1))";;
    esac
done