1

我想用 bash-dialog 创建一个简单的对话框。我使用 (X)DSL 和 bash-3.2。最新的 (X)DSL 基于 Linux 2.4.31 并附带 bash-2.05,但是 bash-3.2 可从 MyDSL/Testing 下载。因此,我的脚本在“#!/bin/bash-3.2/bin/bash”下运行。

用户可以选择的菜单项来自数据库。

示例数据库文件“骨架”:

室内照明|室内照明

户外照明|户外照明

我从“骨架”文件中将数据检索到数组“选项”中:

options=($(awk -F"|" '{ print $1,$2 }' 骨架)

并在终端“回显”数组:

回声 ${options[@]}

这表明:

“室内电枢” “室内照明” “户外电枢” “户外照明”

这看起来可以用作带有“whiptail”的选择菜单,但事实并非如此。命令行:

whiptail --clear --title "骨架" --menu "选择骨架" 50 80 10 ${options[@]}

显示:

column1-column2

室内电枢

照明用

室内使用

户外电枢

照明用

户外使用

代替:

column1-column2

室内电枢-室内照明

户外电枢-户外照明

似乎带有双引号的数组元素被“whiptail”忽略或看不到。我也尝试过“${options[@]}”,但这总是在第一个单词“Indoor”上产生。

除了'whiptail',我尝试了'dialog',但它们是相同的:版本信息在两种情况下都显示'cdialog(ComeOn Dialog!)版本1.1-20080316'。

我的资源非常有限,我不想冒险(还)进入“xdialog”、“zenity”、“dzen”之类的东西,即使这样可以解决这个问题。由于 XDSL(用于 XBOX),我也仅限于 Linux 2.4.31。

我一直在浏览互联网,但无济于事。'whiptail/dialog' 的解决方案是什么?

4

2 回答 2

2

您遇到的基本问题来自 shell 解析命令行的顺序:它在用变量的值替换变量之前解析(并删除)引号和转义,并且它永远不会返回并重新解析其中的任何引号或转义替换的值。考虑这个例子:

var='"foo bar"'   # Note that the single-quotes will be removed, and the
                  # double-quotes will be treated as part of the variable value.
somecmd $var   # This runs cmd with 2 arguments: '"foo' and 'bar"'

就您而言,我不确定双引号的来源;它们不在您提供的文件列表中,并且 awk 命令不会添加它们。但无论如何,您不希望它们存储为值的一部分,而是希望它们围绕变量引用:

var='foo bar'   # Again, the single-quotes are removed.
somecmd "$var"   # This runs cmd with a single argument: 'foo bar'

由于您使用的是数组,因此您的情况有点复杂,但同样的原则也适用。注意echoing 一个变量是高度误导的;如果它显示看起来像正确的引用,那实际上意味着有一些可怕的错误,因为它应该在引用删除后显示参数。

那么,你如何解决呢?尝试这个:

options=()
while IFS="|" read col1 col2 || [ -n "$col1" ]; do
    options+=("$col1" "$col2")  # Note the double-quotes around the variable references
done <armatures
echo "options:"
printf "  '$s'\n" "${options[@]}"  # This prints each array element on a separate line
whiptail --clear --title "Armatures" --menu "Choose an armature" 50 80 10 "${options[@]}"  # Again, double-quotes around the reference

更新:我添加了一个测试([ -n "$col1" ])来为数据库文件中未终止的最后一行执行循环。

如果双引号实际上在数据库文件中,则必须删除它们;处理此问题的最简单方法可能是在将字符串添加到数组时去除引号,在构建数组时使用 bash 的字符串替换功能(将 '"' 替换为空白):

options=()
while IFS="|" read col1 col2 || [ -n "$col1" ]; do
    options+=("${col1//'"'/}" "${col2//'"'/}")
done <armatures
于 2013-06-03T17:11:20.250 回答
1

主要问题在于 bash(或任何其他 shell)将命令行拆分为“单词”的方式,如第一个答案中所述。行拆分是基于 IFS(内部字段分隔符)完成的,默认情况下设置为 <space><tab><newline>。开发早期 shell 的聪明人(Stephen Bourne 等)显然认为用户能够更改它是一个好主意。可以将其设置为多字符值也很好。

因此,您真正需要做的就是将字段分隔符设置为换行符,运行 awk 脚本,然后将其设置回来。您还应该在使用数组时引用它。

这应该适用于 bash:

IFS=$'\n'
options=($(awk -F"|" '{ print $1,$2 }' armatures)
IFS=$' \t\n'

数组成员现在已正确定义。然后:

whiptail --clear --title "Armatures" --menu "Choose an armature" 50 80 10 "${options[@]}"

对于像 Bourne Shell 这样的更原始的 shell,您可能需要通过输入 "IFS="(不带引号)、打开单引号、按 <Enter>,然后用单引号关闭来设置 IFS。要再次重置它,请输入 "IFS="(不带引号),打开单引号,输入 <space>,引用(例如 Ctrl-V)一个 <tab>,按 <Enter>,然后用单引号关闭。

于 2016-01-30T02:08:25.253 回答