从动态列表创建交互式 Shell 提示菜单?

Create an interactive Shell prompt menu from a dynamic list?

下面的提示应该允许用户根据输出到数组的填充列表创建一个selection,然后打印列表及其索引,并要求用户select列表中的一个数字,然后将其设置为一个变量。只允许一个选择,如果用户指定了错误的选项,脚本将提示select一个正确的数字。

Multiple devices detected, please select one from the list:
1. Device1
2. Device2
3. Device3

1
You have selected device Device1

下面的代码不起作用并且有很多语法错误,首先我希望脚本检测 arr=($(ip ad|awk '/state UP/ {print }')) 的输出是否包含多个条目,如果是 运行 脚本,否则设置一个默认值。 case 语句不是动态的,但是,如果像下面这样的 case 超过 2 个,它将失败,也许是一个循环?

host_interfaces()
{
   arr=($(ip ad|awk '/state UP/ {print }'))
   echo "Multiple devices detected, please select one from the list:"
   for i in "${!arr[@]}"; do
   printf "%s%s\n" "$i.  " "${arr[$i]}"
   done
   PS3='Please enter your choice: '
   select opt in "${arr[@]}"
   do
      case $opt in
            "$opt")
               echo "You have selected device $opt"
               export HOST_INTERFACE=$opt
               ;;
            *) echo "invalid option
               break
               ;;
      esac
   done
}

解决方案:

#! /bin/bash

declare HOST_INTERFACE=

function host_interfaces() {
    local -a arr=($(ip ad | awk '/state UP/ {gsub(/:/, "", ); print }'))
    if [ "${#arr[@]}" -eq 1 ]; then
        HOST_INTERFACE="${arr[0]}"
        return 0
    fi
    local opt=
    HOST_INTERFACE=
    echo "Multiple devices detected, please select one from the list:"
    PS3='Please enter your choice: '
    # Add "Quit" value to the items
    select opt in "${arr[@]}" Quit; do
        # "opt" does not contains the number but the associated value
        case $opt in
            "Quit")
                # 
                break
            ;;
            "")
                # No value found
                echo "invalid option"
            ;;
            *)
                echo "You have selected device $opt"
                export HOST_INTERFACE=$opt
                break
            ;;
        esac
    done
}

host_interfaces

也许是这个?

host_interfaces()
{
  local opt='' h=''
  arr=($(ip ad|awk '/state UP/ {print }'))
  if [ "${#arr[@]}" -eq 1 ]; then
    echo "One single device detected"
    h="${arr[0]}"
  elif [ "${#arr[@]}" -gt 1 ]; then
    echo "Multiple devices detected, please select one from the list:"
    PS3='Please enter your choice: '
    select opt in "${arr[@]}"
    do
      case "$opt" in
        "")
          echo "Invalid choice"
          h=''
          ;;
        *)
          echo "You have selected device $opt"
          h="$opt"
          break
          ;;
      esac
    done
  else
    echo "No device detected"
  fi
  echo "Selected device: ${h:-none}"
  export HOST_INTERFACE="$h"
  [ -z "$h" ] && return 1 || return 0
}

请注意函数 returns 1 如果没有找到或选择有效的设备,否则为 0。因此您可以将它用于:

if host_interfaces; then
  echo "HOST_INTERFACE = $HOST_INTERFACE"
else
  echo "No device selected"
fi

这里可以简单地使用dialog

dialog --backtitle "Device selection" --title "Multiple devices detected" --menu "please select one from the list:" 10 45 4 1 "Device1" 2 "Device2" 3 "Device3"

man dialog