Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash script, case statement and sub-menus

Tags:

bash

I wish to run a script with a case statement leading to choices between other lists of choices (sort of sub-menus) between scripts :

#!/bin/bash

echo "Your choice ?"
echo "1) Foo"
echo "2) Bar"
echo "3) Stuff"
read case;

case $case in

#and this is where I would like to allow 
#(here a simplified example I do not manage to code)

1) What script ?    # may I use another case statement ?
    a) Foo1;;
    b) Foo2;;
2) What script ?    # d°
    a) Bar1;;
    b) Bar2;;
    c) Bar3;;

esac

Foo1, Foo2, Bar1, Bar2 and Bar3 being in fact bash scripts, I would like to call, eg, sh Foo1 from within the script.

How must I proceed : May I include a case statement within a case statement (better than if statement, if the choices are numerous) ? And how do I call a script from within another script ?

Thanks in advance for your help

ThG

like image 838
ThG Avatar asked Feb 25 '26 08:02

ThG


2 Answers

Dennis' answer should do what you want. Just to illustrate how to do it with functions, so as to make the script more readable:

function which_foo {
    local foo_options=("foo1" "foo2" "cancel")
    local PS3="Select foo: "

    select foo in "${foo_options[@]}"
    do
        case $REPLY in
            1) ./foo1.sh
               break ;;

            2) ./foo2.sh
               break ;;

            3) break ;;
        esac
    done
}

ACTIONS=("foo" "bar" "quit")
PS3="Select action: "

select action in "${ACTIONS[@]}"
do
    case $action in
         "foo") which_foo
                break ;;

         "bar") which_bar # Not present in this example
                break ;;

        "quit") break ;;
    esac
done

As an aside, note:

  • the use of $REPLY in the case inside which_foo, which is automatically set to the number selected by the user, instead of the text of the option.
  • the use of break in each case options. Without them, select puts you in a loop, so the user would be asked to enter a choice again.
  • that select never changes the value of PS3 for you, so you have to do it yourself when switching between the different levels of your menu.
like image 84
Rodrigue Avatar answered Feb 27 '26 01:02

Rodrigue


Yes, you can nest case statements. You should also consider using a select statement instead of all those echo and read statements.

options=("Option 1" "Option 2" "Option3" "Quit")
optionsprompt='Please enter your choice: '

sub1=("Option 1 sub 1" "Option 1 sub 2")
sub1prompt='Please enter your choice: '

PS3=$optionsprompt
select opt in "${options[@]}"
do
    case $opt in
        "Option 1")
            echo "you chose choice 1"
            PS3=$sub1prompt
            select sub1opt in "${sub1[@]}"
            do
                case $sub1opt in
                    "Option 1 sub 1")
                        echo "you chose choice 2"
                        ;;
                    "Option 1 sub 2")
                        echo "you chose choice 2"
                        ;;
                 esac
            done
            ;;
        "Option 2")
            echo "you chose choice 2"
            ;;
        "Option 2")
            echo "you chose choice 3"
            ;;
        "Quit")
            break
            ;;
        *) echo invalid option;;
    esac
done

The first level menu would look like this:

1) Option 1
2) Option 2
3) Option3
4) Quit
Please enter your choice:

However, that can get very hairy very quickly. It would be better to break it up into functions where the inner select/case statements are in separate functions or are abstracted so you can pass arguments to control them.

To call another script, you might want to set a variable that holds the directory. It would look something like this:

basedir=/some/path

case ...
...
    $basedir/Foo    # call the script
like image 31
Dennis Williamson Avatar answered Feb 27 '26 01:02

Dennis Williamson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!