我打算用来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
进一步阅读: