首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >以编程方式定义whiptail radiolist的Bash咒语

以编程方式定义whiptail radiolist的Bash咒语
EN

Stack Overflow用户
提问于 2019-05-01 08:02:51
回答 2查看 749关注 0票数 1

我想发出一个类似下面这样的bash命令:

代码语言:javascript
复制
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是要在whiptail对话框中突出显示的radiolist项。

这是我目前为构建命令行所做的努力。这可能太复杂了。

代码语言:javascript
复制
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中缺少反斜杠:

代码语言:javascript
复制
set -xv 
++ whiptail --title 'Select Database' --radiolist 'Select Database:' 10 80 2 '
  1 production  off
  2 localhost  on '

解决方案需要提供一种方法,以某种方式知道用户做出了哪些选择,或者是否按了ESC。ESC通常将返回代码设置为255,因此这不是很困难,但是当尝试检索用户选择的radiolist项的值时,这个问题会变得非常混乱。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-05-01 08:17:12

以下内容遵循BashFAQ #50中列出的最佳实践

代码语言:javascript
复制
# 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来测试,但上面代码运行的确切调用完全相同于:

代码语言:javascript
复制
whiptail --title "Select Database" \
         --radiolist "Select Database:" 10 80 2 \
          1 production off \
          2 localhost on 

...as一个字符串,当执行evaled时,它运行精确的命令,可以用以下命令生成:

代码语言:javascript
复制
printf '%q ' whiptail "${whiptail_args[@]}"; echo
票数 4
EN

Stack Overflow用户

发布于 2019-05-01 08:19:30

使用数组。他们会让这件事变得简单十倍。让我们从小事做起,一路向上。下面是数组形式的$DBS$DB_COUNT

代码语言:javascript
复制
DBS=(production localhost)
DB_COUNT=${#DBS[@]}

这里的优点是$DBS实际上有两个条目,所以我们可以使用${#DBS[@]}来计算条目的数量,而不必向外部命令(如wc )提供外壳。

所以现在让我们来处理$DB_LIST。您正尝试在每次循环迭代中添加几个选项。让我们将其转换为数组语法,使用array+=(foo bar baz)来追加项。

代码语言:javascript
复制
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

反斜杠和换行符是由shell解释的,而不是whiptail。不需要将它们放入数组中,所以我去掉了整个$SLASH变量。换行符无关紧要,所以再见echo ""

最后,让我们运行whiptail。不再需要所有疯狂的引用和eval-ing。我们可以直接运行它,并在正确的位置扩展我们构建的数组。

代码语言:javascript
复制
whiptail --title "Select Database" --radiolist "Select Database:" 10 80 "$DB_COUNT" "${DB_LIST[@]}"

还有更多的清理工作可以完成,但我认为这一天已经足够了。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55930117

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档