在脚本shell中选择多个选项?

时间:2015-05-22 23:54:08

标签: bash shell sh

我想创建一个带有多选脚本的菜单。 喜欢:

1) 

2)

3)

4)

5)

我可以同时选择1,3和5。

1 个答案:

答案 0 :(得分:5)

bash select复合命令不直接支持多种选择,但你仍然可以基础你的解决方案,无论用户输入的是什么,都会记录在特殊的$REPLY变量中:

#!/usr/bin/env bash

choices=( 'one' 'two' 'three' 'four' 'five' ) # sample choices
select dummy in "${choices[@]}"; do  # present numbered choices to user
  # Parse ,-separated numbers entered into an array.
  # Variable $REPLY contains whatever the user entered.
  IFS=', ' read -ra selChoices <<<"$REPLY"
  # Loop over all numbers entered.
  for choice in "${selChoices[@]}"; do
    # Validate the number entered.
    (( choice >= 1 && choice <= ${#choices[@]} )) || { echo "Invalid choice: $choice. Try again." >&2; continue 2; }
    # If valid, echo the choice and its number.
    echo "Choice #$(( ++i )): ${choices[choice-1]} ($choice)"
  done
  # All choices are valid, exit the prompt.
  break
done

echo "Done."

关于select命令通常如何工作,选择

  • 运行man bash并查看“复合命令”标题
  • 有关带注释的示例,请参阅this answer

答案实现自定义逻辑,如下所示:

  • 忽略select命令的指定目标变量dummy,而使用$REPLY变量,因为Bash将其设置为用户输入的任何内容(未经验证)。
  • IFS=', ' read -ra selChoices <<<"$REPLY"将用户输入的值标记为:
    • 通过here-string<<<)向read命令
    • 投放
    • 使用逗号和空格实例(,<space>)作为[内部]字段分隔符(IFS=...
      • 请注意,作为副作用,用户只能使用空格来分隔他们的选择。
    • 并将生成的标记存储为数组元素(-aselChoices; -r只是关闭\字符的解释。在输入
    • for choice in "${selChoices[@]}"; do遍历所有令牌,即用户选择的个别号码。
    • (( choice >= 1 && choice <= ${#choices[@]} )) || { echo "Invalid choice: $choice. Try again." >&2; continue 2; }确保每个令牌都有效,即它是介于1和所提供选择计数之间的数字。
  • echo "Choice #$(( ++i )): ${choices[choice-1]} ($choice)"输出每个选项和选项编号
    • 以运行索引(i)作为前缀,使用arithmetic expansion++i)递增($((...))) - 因为变量默认为{{1}在算术上下文中,第一个索引输出将是0;
    • 后跟1,即由输入的数字指示的选择字符串,递减${choices[choice-1]},因为Bash数组是基于1的;请注意0如何在数组下标中不需要choice前缀,因为下标是在算术上下文中计算的(就像在$内),如上所述。
    • $(( ... ))终止,所选数字在括号中。
  • 退出提示需要
  • ($choice);默认情况下,break会一直提示。