Bash case语句在输入无效时重新启动 [英] Bash case statement restart on invalid input

查看:55
本文介绍了Bash case语句在输入无效时重新启动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

试图找出一种返回案例陈述的方式.例如,如果您运行此....

Trying to figure out a way to return in a case statement. For example, if you run this....

while :
do 
    clear
    cat<<-EOF
    ======================
    Foo Bar Doo Dah Setup
    ======================

    (1) Foo
    (2) Bar
    (q) Quit

    ----------------------
    EOF
    read
    case $REPLY in
    "1")  foo="foo" ;;
    "2")  bar="bar" ;;
    "q")  break     ;;
     * )  echo "Invalid Option"
    esac
    sleep .5

    clear
    cat<<-EOF
    ======================
    Foo Bar Doo Dah Setup
    ======================

    (1) Doo
    (2) Dah
    (q) Quit

    ----------------------
    EOF
    read
    case $REPLY in
    "1")  doo="doo" ;;
    "2")  dah="dah" ;;
    "q")  break     ;;
     * )  echo "Invalid Option"
    esac
    sleep .5

done

...然后输入无效选项",您会注意到它移至下一个案例,而不是重新评估该案例.

...and enter an "Invalid Option" then you'll notice it moves on to the next case instead of re-evaluating the case.

解决方法还不错,只需要在while循环内将case语句嵌套到if语句中即可.

The workaround isn't too bad just have to nest the case statement into an if statement within a while loop ...

while read; do
    if [ $REPLY -ge 1 -a $REPLY -le 2 ]; then
        case $REPLY in
        "1")  foo="foo" ;;
        "2")  bar="bar" ;;
        esac
        break
    elif [ $REPLY == q ]; then 
        break
    else
        echo "Invalid Option"
    fi
done

话虽这么说,有谁知道某种形式的循环控制从案例选择中重新运行案例语句?

That being said seems a bit much, anyone know of some form a loop control to rerun a case statement from a case selection?

推荐答案

如果在继续下一个菜单之前需要从菜单中进行有效选择,则需要循环进行选择过程.您可能还应该计算失败次数,并在一定数量的连续失败(例如10次)后终止.

If you need a valid choice from the menu before continuing to the next menu, then you need a loop around the choosing process. You should probably also count the failures and terminate after some number of consecutive failures such as 10.

shell循环构造同时支持 break continue ,并且可以在其后跟随一个数字,该数字指示应打破多少个循环级别(默认级别数)是1).

The shell loop constructs support both break and continue, and these can optionally be followed by a number indicating how many loop levels should be broken (the default number of levels is 1).

该代码还应注意 read 检测到的EOF并终止循环.这是通过以下代码中的 answer 变量实现的.

The code should also heed EOF detected by read and terminate the loops. That's achieved with the answer variable in the code below.

这导致代码如下:

retries=0
max_retries=10
while [ $retries -lt $max_retries ]
do 
    clear
    cat <<-'EOF'
    ======================
    Foo Bar Doo Dah Setup
    ======================

    (1) Foo
    (2) Bar
    (q) Quit

    ----------------------
    EOF
    retries=0
    answer=no
    while read
    do
        case "$REPLY" in
        "1")  foo="foo"; answer=yes; break;;
        "2")  bar="bar"; answer=yes; break;;
        "q")  break 2;;  # Or exit, or return if the code is in a function
         * )  echo "Invalid Option ('$REPLY' given)" >&2
              if [ $((++retries)) -ge $max_retries ]; then break 2; fi
              ;;
        esac
    done
    if [ "$answer" = "no" ]; then break; fi   # EOF in read loop

    sleep .5

    clear
    cat <<-'EOF'
    ======================
    Foo Bar Doo Dah Setup
    ======================

    (1) Doo
    (2) Dah
    (q) Quit

    ----------------------
    EOF
    retries=0
    answer=no
    while read
    do
        case $REPLY in
        "1")  doo="doo"; answer=yes;;
        "2")  dah="dah"; answer=yes;;
        "q")  break 2;;
         * )  echo "Invalid Option ('$REPLY' given)"" >&2
              if [ $((++retries)) -ge $max_retries ]; then break 2; fi
              ;;
        esac
    done
    if [ "$answer" = "no" ]; then break; fi   # EOF in read loop
    sleep .5
    echo "$foo$bar $doo$dah"   # Do something with the entered information
done

我并不完全热衷于 read ,后面没有名称,这尤其是因为它是Bash扩展而不是标准的Shell功能(POSIX

I'm not entirely keen on read with no name after it, not least because it is a Bash extension rather than standard shell functionality (the POSIX read utility does not provide a default variable name), and omitting the name unnecessarily limits the scripts portability.

还请注意,here文档的起始标记用引号引起来,因此here文档的内容不会受到shell扩展的影响.-表示已从此处文档和文档标记行的末尾删除了开头的制表符(但没有空格).

Note, too, that the here documents have the start marker enclosed in quotes so that the content of the here document is not subjected to shell expansions. The - indicates that leading tabs (but not spaces) are deleted from the here document and the end of document marker line.

也可以通过使用 continue 而不是嵌套的 while 循环来修复"第一个循环问题中的代码.但是,如果第二个循环仅重试第二个提示,那么继续外部循环并跳过第一个菜单将很复杂.显示的解决方案是对称的,并且可以正确隔离两个提示中的每一个的输入.

The code in the question for the first loop could also be 'fixed' by using a continue instead of a nested while loop. However, if the second loop was to retry just the second prompt, continuing the outer loop and skipping the first menu would be complex. The solution shown is symmetric and properly isolates the input for each of the two prompts.

我选择了不重试菜单,但也不会很难在该代码上循环.使用以下方法将是可行的:

I chose not to re-echo the menu on a retry, but it would not be hard to loop on that code too. It would be feasible to use:

retries=0
answer=no
while   clear
        cat <<-'EOF'
        ======================
        Foo Bar Doo Dah Setup
        ======================

        (1) Foo
        (2) Bar
        (q) Quit

        ----------------------
        EOF
        read
do
    …processing $REPLY as before…
done

但是,这样做会导致很多人头痛,因为人们并不经常意识到在 while 语句之后可以有一个命令列表,并且只有最后一个的退出状态才能控制是否循环是否继续另一个迭代.

However, doing so will cause many scratched heads as people are not often aware that you can have a list of commands after a while statement and it is only the exit status of the last that controls whether the loop continues another iteration or not.

我个人避免在shell脚本中使用制表符,因此我可能会创建变量来保存菜单:

I personally avoid tabs in shell scripts, so I'd probably create variables to hold the menus:

menu1=$(cat <<-'EOF'
======================
Foo Bar Doo Dah Setup
======================

(1) Foo
(2) Bar
(q) Quit

----------------------
EOF
)

那么循环中的提示可能是:

The prompt in the loop could then be:

while clear; echo "$menu1"; read

这更容易理解(并且双引号至关重要).如果 clear 命令运行良好并且成功退出,则可以使用&& 代替; .

which is easier to understand (and the double quotes are crucial). You could use && in place of ; if the clear command is well behaved and exits successfully.

这篇关于Bash case语句在输入无效时重新启动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆