我想用bash-dialog创建一个简单的对话框。我使用(X)DSL和bash-3.2。最新的(X)DSL基于Linux 2.4.31,附带了bash-2.05,但是,可以从MyDSL/Testing下载bash-3.2。所以,我的脚本运行在'#!/bin/bash-3.2/bin/bash'下。
用户可以选择的菜单项来自数据库。
示例数据库文件'armatures':
室内照明|室内照明
户外照明|户外照明
我从'armatures'文件中检索数据到数组'options',使用:
选项= ($ (awk -F" |";"{print $1,$2}"
和在终端'echo'中返回数组:
echo ${选项[@]}
显示:
"室内Armatures"室内照明";"户外Armatures"户外照明"
这看起来OK作为一个选择菜单与'鞭尾',但它不是。命令行:
whiptail——clear——title "——菜单"选择电枢"50 80 10 ${options[@]}
节目:
column1-column2
Indoor-Armatures
照明
室内使用
Outdoor-Armatures
照明
户外使用
代替:
column1-column2
室内电枢-室内照明
室外电枢-室外照明
似乎带有双引号的数组元素被忽略或不被'whiptail'看到。我也试过"${options[@]}"但结果总是在第一个单词"Indoor"上。
除了'whiptail'之外,我尝试了'dialog',但它们都是相同的:版本信息显示'cdialog (ComeOn dialog !) version 1.1-20080316'。
我的资源非常有限,而且(目前)不想冒险使用'xdialog', 'zenity', 'dzen'之类的,即使这样可以解决这个问题。由于XDSL(用于XBOX),我也仅限于Linux 2.4.31。
我一直在浏览互联网,但无济于事。"鞭尾/对话"的解决方案是什么?
您遇到的基本问题来自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命令也不会添加它们。但是在任何情况下,你都不希望它们作为值的一部分存储,你希望它们围绕在变量reference:
var='foo bar' # Again, the single-quotes are removed.
somecmd "$var" # This runs cmd with a single argument: 'foo bar'
你的情况有点复杂,因为你使用的是一个数组,但同样的原则适用。注意,echo
是一个非常容易误导人的变量;如果它显示了看起来正确的引号,那实际上意味着有一些可怕的错误,因为它应该在后显示参数。
怎么解呢?试试这个:
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
主要问题在于bash(或任何其他shell)将命令行分成"单词"的方式,正如第一个答案中提到的那样。分隔行是在IFS(内部字段分隔符)的基础上完成的,它被设置为
因此,您真正需要做的就是将字段分隔符设置为换行符,运行awk脚本,然后将其设置回来。当你使用数组时,你也应该引用它。
这应该适用于bash:
IFS=$'n'
options=($(awk -F"|" '{ print $1,$2 }' armatures)
IFS=$' tn'
数组成员现在被正确定义。然后:
whiptail --clear --title "Armatures" --menu "Choose an armature" 50 80 10 "${options[@]}"
对于像Bourne Shell这样更原始的Shell,您可能需要通过输入"IFS="(不带引号),打开单引号,按