Bash 脚本、case 语句和子菜单

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4728320/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 23:17:39  来源:igfitidea点击:

Bash script, case statement and sub-menus

bash

提问by ThG

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

我希望运行一个带有 case 语句的脚本,导致在脚本之间的其他选项列表(某种子菜单)之间进行选择:

#!/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.

Foo1、Foo2、Bar1、Bar2 和 Bar3 实际上是 bash 脚本,我想从脚本中调用例如 sh Foo1。

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 ?

我必须如何进行:我可以在 case 语句中包含 case 语句吗(如果选项很多,比 if 语句更好)?以及如何从另一个脚本中调用脚本?

Thanks in advance for your help

在此先感谢您的帮助

ThG

ThG

回答by Paused until further notice.

Yes, you can nest casestatements. You should also consider using a select statement instead of all those echoand readstatements.

是的,您可以嵌套case语句。您还应该考虑使用 select 语句而不是所有这些echoread语句。

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/casestatements are in separate functions or are abstracted so you can pass arguments to control them.

但是,这会很快变得非常毛茸茸。最好将其分解为函数,其中内部select/case语句位于单独的函数中或被抽象,以便您可以传递参数来控制它们。

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

回答by Rodrigue

Dennis' answershould 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 $REPLYin the caseinside which_foo, which is automatically set to the number selected by the user, instead of the text of the option.
  • the use of breakin each caseoptions. Without them, selectputs you in a loop, so the user would be asked to enter a choice again.
  • that selectnever changes the value of PS3for you, so you have to do it yourself when switching between the different levels of your menu.
  • 使用$REPLYin caseinside which_foo,它会自动设置为用户选择的数字,而不是选项的文本。
  • break在每个case选项中的使用。没有它们,select您将陷入循环,因此将要求用户再次输入选择。
  • select永远不会改变您的价值PS3,因此在菜单的不同级别之间切换时,您必须自己做。