Jonathan Lafleur
Jonathan Lafleur

Reputation: 493

Scripting a menu with selection indicator in bash

I'm really new in bash scripting and I'm currently automating my project creation process.

I've done a lot of work right now but i'm thinking about changing my installation plugins part... Could someone take a look at this script that I've found on serverfault and modified with my needs, but I don't really understand the whole process... If someone could point me a place where I can learn it or maybe comment this code for me...

Thank you in advance, i'll modify the code on my own after understanding it.

    #!/bin/bash

    # customize with your own.
    options=("advanced-custom-fields-pro" "analytics360" "better-wp-security" "debug-bar" "debug-bar-console" "debug-bar-cron" "email-address-encoder" "force-regenerate-thumbnails" "gravityforms" "gravityforms-multilingual" "hansel-gretel" "log-deprecated-notices" "log-deprecated-notices-extender" "maintenance" "Maintenance-pro" "mshare" "post-duplicator" "responsive-lightbox" "sitepress-multilingual-cms" "what-the-file" "wordpress-seo" "wp-realtime-sitemap" "Exit")

    menu() {
        echo -e "\033[1mPlease select the plugin you want to install :\033[0m"
        for i in ${!options[@]}; do 
            printf "%3d%s) %s\n" $((i+1)) "${choices[i]:- }" "${options[i]}"
        done
        [[ "$msg" ]] && echo "$msg"; :
    }

    prompt="Enter the digit representing the plugin you need : "
    while menu && read -rp "$prompt" num && [[ "$num" ]]; do
        [[ "$num" != *[![:digit:]]* ]] &&
        (( num > 0 && num <= ${#options[@]} )) ||
        { msg="Invalid option: $num"; continue; }
        ((num--)); msg="${options[num]} was ${choices[num]:+un}checked"
        [[ "${choices[num]}" ]] && choices[num]="" || choices[num]="+"
    done

    printf "You selected"; msg=" nothing"
    for i in ${!options[@]}; do 
        [[ "${choices[i]}" ]] && { printf " %s" "${options[i]}"; msg=""; }
    done
    echo "$msg"

This code right now only told which option have been selected and display a + in front of the choice when it has been selected and remove the + when it called again... What I need is to add the + when selected, and don't allow the user to use it again, then when selected it has to launch another function with the selection name in parameter.

Thank you for your help I really appreciate, and like I already told, i'm really up to do it myself if someone point me the right doc to read, and if possible comment out this script.

Upvotes: 0

Views: 1541

Answers (1)

damian1baran
damian1baran

Reputation: 1397

Ok - I will do my best to help you (so you can learn something from this bash script) with comments and little bit of explanation to current code:

#!/bin/bash

# -- ASSIGNMENT OF ARRAY OF VALUES TO OPTIONS VARIABLE --
# This line below is basically array of options/strings
# assigned to variable "options" used later on.
# Try to copy paste this whole line into Linux Bash (shell)
# and then try to execute following command "echo ${options[0]}"
# without quotes. Then you can try also "echo ${options[1]}", etc.
options=("advanced-custom-fields-pro" "analytics360" "better-wp-security" "debug-bar" "debug-bar-console" "debug-bar-cron" "email-address-encoder" "force-regenerate-thumbnails" "gravityforms" "gravityforms-multilingual" "hansel-gretel" "log-deprecated-notices" "log-deprecated-notices-extender" "maintenance" "Maintenance-pro" "mshare" "post-duplicator" "responsive-lightbox" "sitepress-multilingual-cms" "what-the-file" "wordpress-seo" "wp-realtime-sitemap" "Exit")

# -- MENU FUNCTION DEFINITION --
# This "menu" function below is nothing more than printing
# of all array elements to your screen. You can try to type
# it manually to your shell. You will certainly find similarities
# in for loop and printf functions from HarvardX CS50X course :-)
# Or just copy paste whole "menu" function to your shell and then
# invoke menu function by typing "menu" into bash shell without quotes.
# Little bit description to "echo -e". Special characters
# "\033[1m...\033[0m" just says change font color between these two
# special values of "echo -e" argument to white".
# Just try to execute:  echo -e "\033[1mPlease select the plugin you want to install :\033[0m"
# and compare to:  echo -e "Please select the plugin you want to install :"
# Basically if you are not using this special formatting it is ok to
# use just: echo "Please select the plugin you want to install"
menu() {
    echo -e "\033[1mPlease select the plugin you want to install :\033[0m"
    for i in ${!options[@]}; do 
        printf "%3d%s) %s\n" $((i+1)) "${choices[i]:- }" "${options[i]}"
    done
    [[ "$msg" ]] && echo "$msg"; :
}

# -- CONDITION OF THE WHILE LOOP --
# This is little bit more complicated but first line only
# assign string to prompt variable named "prompt" - used later on.
# "While" line says (correct me if I am wrong) - do it again
# and again an again till return code of "menu" invoked function
# specified above and return code of "read -rp" program are "0" (ok)
# and also following [[ "$num" ]] tests if "num" variable has been
# assigned with a value - if it was it returns "0" (ok) if it wasn't
# it returns "1" (error) what will cause while loop to repeat.
# -- BODY OF THE WHILE LOOP --
# Body of the while loop is also bit complicated. First line is
# regular expression which checks if "num" variable contains only number
# AND second line checks if "num" is larger than 0 and less than or
# equal number of array elements from array "options". If
# these conditions are not met OR operation ensure that "msg" variable
# will contain error statement "Invalid option, etc.". "Continue" says
# to not interrupt while loop and continue execution of other statements
# from this while loop. Rest of this while body is about checking 
# and un-checking of choices. If you choose some option form menu
# value "+" is assigned to variable "choices[num]". If "choices[num]"
# contains value then "msg" contains "checked" AND choices[num]="+"    
# otherwise "unchecked" AND choices[num]="".
# You can try to execute "echo ${#options[@]}" whiteout quotes.
# You will see it holds number of array elements.
prompt="Enter the digit representing the plugin you need : "
while menu && read -rp "$prompt" num && [[ "$num" ]]; do
    [[ "$num" != *[![:digit:]]* ]] &&
    (( num > 0 && num <= ${#options[@]} )) ||
    { msg="Invalid option: $num"; continue; }
    ((num--)); msg="${options[num]} was ${choices[num]:+un}checked"
     && choices[num]="" || choices[num]="+"
done

# -- FOR LOOP --
# Just prints all checked options to the screen.
# Evaluation which one are printed and which are not is done by
# [[ "${choices[i]}" ]] which returns 0 if it contains value
# and returns 1 if it doesn't contain value.
# TEST NUMBER 1
# You can check return value e.g.:
# execute following: test=
# execute following: [[ $test ]]
# execute following: echo $?
# displayed is return value - hopefully 1 :)
# TEST NUMBER 2
# execute following: test=3
# execute following: [[ $test ]]
# execute following: echo $?
# displayed is return value - hopefully 0 :)
printf "You selected"; msg=" nothing"
for i in ${!options[@]}; do 
    [[ "${choices[i]}" ]] && { printf " %s" "${options[i]}"; msg=""; }
done
echo "$msg"

Upvotes: 1

Related Questions