Switch case 在 Shell 中不起作用

Switch case 在 Shell 中不起作用

我打算用来gdialog获取用户输入并将其提供给 shell 中的 switch case。下面是我的代码:

#!/bin/sh


which gdialog 2> /dev/null && DIALOG=gdialog || DIALOG=dialog

end () {
    # rm -f $FILE1 $FILE2 $ERROR
    echo "User pressed cancel!"
exit
}

while true
do
    choice=$($DIALOG --title "Messenger" --menu "Command" 8 35 8 \
    "Date" "Get today's date" \
    "Time" "Get today's time")|| end

    # echo $choice

    case "$choice" in
            "Date")

            MSG="Date is requested"
            echo $MSG
            $DIALOG --yesno "$MSG" 7 20 || end          
     ;;
            "Time")
            MSG="Time is requested!"
            $DIALOG --yesno "$MSG" 7 20 || end          
     ;;
    esac
done

问题是 switch case 执行,控制流到达第一个 case 或第二个 case,但MSG变量声明后的行未执行。我打算使用 yes/no 询问用户是否要继续gdialog。我在这里做错了什么?

答案1

命令替换被命令的标准输出替换。对话框使用 stdout 来显示它的 UI,gdialog afaik 根本不使用它。两者都使用 stderr 返回结果。

让脚本按预期工作的一种方法是在命令替换中将 stdout 与 stderr 交换:

choice=$($DIALOG --title "Messenger" --menu "Command" 8 35 8 \
"Date" "Get today's date" \
"Time" "Get today's time" 3>&2 2>&1 1>&3)|| end

答案2

dialog会将其结果写入标准错误,除非您使用重定向进行一些解决方法,或者使用该--stdout选项(因为,像任何curses应用程序一样,它默认将其显示写入标准输出,并报告标准错误)。您不会注意到 with gdialog,因为它将其显示写入另一个窗口。

正因为如此,gdialog才会写没有什么到标准输出,并且$choice将为空。该脚本将执行 case 语句,但不匹配任何 case。一般来说,case 语句应该有一个默认值,例如,*)以便您可以留言那里看看发生了什么。

不是问题的一部分,但是如何解决这个问题似乎是意料之中的。该脚本引用gdialog,这可能是一个脚本调用zenity原来的gdialog早就没了)。两者都没有--stdout选择,尽管这可能早于任何一个计划(参见2000 年以来的变更日志条目)。您可以在 shell 中通过将文件描述符交换为标准输出和错误来解决这个问题。自 2000 年底以来,这也已出现在dialog 的示例脚本中,并采用了 Carey Evans(tn5250 开发人员)的建议:

    可以捕获对话框的输出,而无需使用
    根本没有临时文件,就像我在 tn5250 的“xt5250”脚本中所做的那样:

        执行3>&1
        XT5250_HOST="`$DIALOG --backtitle "xt5250" --title "连接到主机" \
          --inputbox "输入要连接的主机的名称或 IP 地址:" \
          7 60 2>&1 1>&3`"
        ret=$?
        执行3>&-

    也许你可以考虑使用这样的东西而不是
    临时文件。额外的 fd 的诡计变得有点难以实现
    不过,请阅读。

    >(尽管它们只是示例 - 我应该花多少工作来确保它们的安全?)

    人们_会_剪切并粘贴它们。

同意这一点,这有助于停止并解释脚本。 bash 文档在这里有帮助,移动文件描述符。这个脚本

(sh myscript.sh 3>&2 2>&1 1>&3) 2>/dev/null

可以从右向左读取为 (a) 移动文件描述符 1 (标准输出) 至 3, 2 (标准错误)到 1,然后是 3(原来标准输出) 至 2。

因此,您可以通过将相同系列的更改粘贴到文件描述符来改进脚本:

3>&2 2>&1 1>&3

在分配给choice

choice=$($DIALOG --title "Messenger" --menu "Command" 8 35 8 \
"Date" "Get today's date" \
"Time" "Get today's time" 3>&2 2>&1 1>&3 )|| end

进一步阅读:

相关内容