LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Bash Script to Create Menu Based on a File List (Map Files List to Numbers) (https://www.linuxquestions.org/questions/programming-9/bash-script-to-create-menu-based-on-a-file-list-map-files-list-to-numbers-4175678369/)

Steve R. 07-08-2020 11:41 AM

Bash Script to Create Menu Based on a File List (Map Files List to Numbers)
 
As part of learning bash scripting, I developed a bash script to undertake an incremental back-up. The next question, was how to obtain a list of the back-up files and to select one (tar) archive file for listing all the files stored in that (tar) archive.

I found the solution here: Create bash menu based on file list (map files to numbers). It ran "right-out-of-the-box" with only obvious minimal tweaking. Seemed well worth re-posting here. See the answer on Ask Ubuntu to get full context. Credit goes to: deltab.


Code:

echo "The following `*.war` archives were found; select one:"

# set the prompt used by select, replacing "#?"
PS3="Use number to select a file or 'stop' to cancel: "

# allow the user to choose a file
select filename in *.war
do
    # leave the loop if the user says 'stop'
    if [[ "$REPLY" == stop ]]; then break; fi

    # complain if no file was selected, and loop to ask again
    if [[ "$filename" == "" ]]
    then
        echo "'$REPLY' is not a valid number"
        continue
    fi

    # now we can use the selected file
    echo "$filename installed"

    # it'll ask for another unless we leave the loop
    break
done


rnturn 07-08-2020 03:08 PM

Quote:

Originally Posted by Steve R. (Post 6143058)
As part of learning bash scripting, I developed a bash script to undertake an incremental back-up. The next question, was how to obtain a list of the back-up files and to select one (tar) archive file for listing all the files stored in that (tar) archive.

I found the solution here: Create bash menu based on file list (map files to numbers). It ran "right-out-of-the-box" with only obvious minimal tweaking. Seemed well worth re-posting here. See the answer on Ask Ubuntu to get full context. Credit goes to: deltab.


Code:

echo "The following `*.war` archives were found; select one:"

# set the prompt used by select, replacing "#?"
PS3="Use number to select a file or 'stop' to cancel: "

# allow the user to choose a file
select filename in *.war
do

<snip>


"select" is "cheap-n-dirty" and fine for a small number of objects but, once I learned that shell scripts could employ arrays, I've always preferred to pull the list of "things" into an array and display "N" of them at a time in a page-oriented fashion. (Where "N" is the user's terminal height minus a few of lines for status, the prompt, and user input.) Yes... you do have to manage the item numbers being displayed (i.e., their location within the array), and increment or decrement them as the user pages through the array/list but I've found that users generally preferred that to scrolling their terminal window to browse through a long list of items that "select" presented. The trickiest bit is parsing the user input and determining whether it's a navigation command or a menu selection. (While it sounds like more work, I can recall one case where there was far, far less friction involved in implementing something like this than to convince the user community to change their application that had a bazillion data files in a single directory. YMMV.)

Cheers...

shruggy 07-08-2020 05:03 PM

^ Yep. I once wrote this as a proof of concept:
Code:

#!/bin/bash -e
# Browse package documentation
# Basic version, uses 'select' statement.
# See doc.bash for a safer and more featureful version of this script.
[[ -n $1 ]] || { echo "Usage: $0 package_name" >&2; exit 1;}
docpfx=/usr/share/doc/
[[ -d $docpfx$1 ]] || { echo "Directory $docpfx$1 not found" >&2; exit 2;}

: ${COLUMNS:=`tput cols`}
GLOBIGNORE=AUTHORS*:ACK*:CONTRIBUTORS*:CREDITS*:THANKS*

lsopts='-Ldpq'

# --group-directories-first is GNU-specific, only add it to ls options
# if we've got GNU ls v.6+.
read lsver < <(ls --version 2>/dev/null) ||:
lsver=${lsver##* }
((${lsver%%.*}+0>=6))&&lsopts+=' --group-directories-first'

shopt -s extglob nullglob checkwinsize
idx=index?(.[a-z][a-z]*).htm?(l) CDPATH=

docmenu () {
  pushd "$1" >/dev/null
  local PS3="...${PWD#$docpfx}> "
  # Grouping index.html first, directories next, then all the rest.
  local -a files=($idx)
  mapfile -tO${#files[@]} files < <(ls $lsopts !($idx))
  select file in "${files[@]}"; do
    [[ $REPLY == [Xx]* ]] && exit
    [[ -z $file ]] && break
    if [[ -d $file ]]; then
      docmenu "$file"
    else
      case $file in
        *.htm?(l)) sensible-browser "$file";;
        *)        sensible-pager  "$file";;
      esac
    fi
  done
  popd >/dev/null
}

pushd "$docpfx" >/dev/null
docmenu "$1"
popd >/dev/null

But the actual script I ended up with is much more sophisticated than this, and doesn't use select at all.


All times are GMT -5. The time now is 04:02 PM.