我要发出类似于以下内容的bash命令:
whiptail --title 'Select Database' --radiolist 'Select Database:' 10 80 2 \
1 production off \
2 localhost on
Whiptail非常特别地关于如何指定无线电列表值。如图所示,必须在各自的行上分别提供它们。 Here is a good article on this question。
数据库列表位于名为DBS
的变量中,而ACTIVE_DB
是在抽签对话框中突出显示的单选列表项。
这是我目前用于构建命令行的工作。可能太令人费解了。
DBS="production localhost"
ACTIVE_DB="localhost"
DB_COUNT="$( echo "$DBS" | wc -w )"
DB_LIST="$(
I=1
echo ""
for DB in $DBS; do
SELECTED="$( if [ "$DB" == "$ACTIVE_DB" ]; then echo " on"; else echo " off"; fi )"
SLASH="$( if (( $I < $DB_COUNT )); then echo \\; fi )"
echo " $I $DB $SELECTED $SLASH"
echo ""
I=$(( I + 1 ))
done
)"
OPERATION="whiptail \
--title \"Select Database\" \
--radiolist \
\"Select Database:\" \
10 80 $DB_COUNT \"${DB_LIST[@]}\""
eval "${OPERATION}"
我离我很近。如您所见,扩展包含单引号,使事情变得混乱,并且某些EOL缺少反斜杠:
set -xv
++ whiptail --title 'Select Database' --radiolist 'Select Database:' 10 80 2 '
1 production off
2 localhost on '
该解决方案需要提供一种方法,以某种方式知道用户进行了哪个选择,或者他们是否按了ESC。 ESC通常将返回码设置为255,这应该不难,但是,当尝试检索用户选择的单选列表项的值时,此问题会变得非常混乱。
答案 0 :(得分:3)
以下遵循BashFAQ #50中列出的最佳做法:
# note that lower-case variable names are reserved for application use by POSIX
# see https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html
active_db="localhost"
dbs=( production localhost ) # using an array, not a string, means ${#dbs[@]} counts
# initialize an array with our explicit arguments
whiptail_args=(
--title "Select Database"
--radiolist "Select Database:"
10 80 "${#dbs[@]}" # note the use of ${#arrayname[@]} to get count of entries
)
i=0
for db in "${dbs[@]}"; do
whiptail_args+=( "$((++i))" "$db" )
if [[ $db = "$active_db" ]]; then # only RHS needs quoting in [[ ]]
whiptail_args+=( "on" )
else
whiptail_args+=( "off" )
fi
done
# collect both stdout and exit status
# to grok the file descriptor switch, see https://stackoverflow.com/a/1970254/14122
whiptail_out=$(whiptail "${whiptail_args[@]}" 3>&1 1>&2 2>&3); whiptail_retval=$?
# display what we collected
declare -p whiptail_out whiptail_retval
虽然我没有方便使用的whiptail
进行测试,但是上面代码运行的确切调用与以下内容完全相同:
whiptail --title "Select Database" \
--radiolist "Select Database:" 10 80 2 \
1 production off \
2 localhost on
...作为字符串,当eval
被运行时,可以使用以下命令生成精确的命令:
printf '%q ' whiptail "${whiptail_args[@]}"; echo
答案 1 :(得分:1)
使用数组。他们会使此操作变得容易十倍。让我们从小处着手,逐步发展。这是$DBS
和$DB_COUNT
的数组形式:
DBS=(production localhost)
DB_COUNT=${#DBS[@]}
这里的优点是$DBS
实际上有两个条目,因此我们可以用${#DBS[@]}
计算条目的数量,而不必使用wc
这样的外部命令。
现在让我们来解决$DB_LIST
。您正在尝试在每个循环迭代中添加几个选项。让我们使用array+=(foo bar baz)
附加项将其转换为数组语法。
DB_LIST=()
I=1
for DB in "${DBS[@]}"; do
if [ "$DB" == "$ACTIVE_DB" ]; then SELECTED=on; else SELECTED=off; fi
DB_LIST+=("$I" "$DB" "$SELECTED")
I=$(( I + 1 ))
done
反斜杠和换行符由外壳程序解释,而不是由鞭尾语言解释。无需将它们放入数组中,因此我摆脱了整个$SLASH
变量。换行无关紧要,echo ""
再见。
最后,让我们挥舞一下。不需要所有疯狂的引号和eval
-了。我们可以直接运行它并扩展在正确位置构建的数组。
whiptail --title "Select Database" --radiolist "Select Database:" 10 80 "$DB_COUNT" "${DB_LIST[@]}"
还有更多清理工作可以完成,但我认为一天就足够了。