Bash技巧:详解用select复合命令的用法,可提供选择菜单项

本篇文章介绍 bash 的 select 复合命令,该命令能够提供菜单列表给用户进行选择。shell

  • select 命令格式
  • select 命令实例
  • 自定义提示信息
  • 修改菜单项的分割字符

select 命令格式

在 Linux 的 Bash shell 中,能够用 select 复合命令 (compound command) 提供一个菜单列表给用户选择,并根据用户的选择进行相应地处理。查看 man bash 里面对 select 命令的说明以下:bash

select name [ in word ] ; do list ; done
The list of words following "in" is expanded, generating a list of items. The set of expanded words is printed on the standard error, each preceded by a number. If the "in word" is omitted, the positional parameters are printed.

The PS3 prompt is then displayed and a line read from the standard input. If the line consists of a number corresponding to one of the displayed words, then the value of name is set to that word. If the line is empty, the words and prompt are displayed again. If EOF is read, the command completes. Any other value read causes name to be set to null. 函数

The line read is saved in the virable REPLY. The list is executed after each selection until a break command is executed. ui

The exit status of select is the exit status of the list command executed in list, or zero if no commands were executed.spa

select 命令格式中,[ in word ] 表示 "in word" 是可选参数,用于提供菜单列表,实际输入的时候不须要输入 [] 这两个字符。而 name 变量会保存用户选择的菜单项内容,能够获取 name 变量值来查看用户的选择。每次用户输入选择后,会执行 list 指定的命令。翻译

注意:这里的 [] 并非 bash 里面的条件判断命令。Bash 有一个 [ 条件判断命令,其格式是 [ 参数... ],二者格式比较类似,注意区分,不要搞混。code

当没有提供 in word 参数时,select 命令默认使用 in "$@" 参数,也就是传入脚本、或者传入函数的参数列表来做为菜单选项。字符串

select 命令使用 in word 参数来指定菜单列表,不一样的菜单项之间用空格隔开,不要用双引号把整个菜单列表括起来,不然会被当成一个菜单项。input

当用双引号把菜单列表括起来时,整个菜单列表被当成一个选项。若是某个选择项的内容确实要包含空格,就能够单独用双引号把这个选择项的内容括起来,避免该选项该分割成多个选项。it

选择以后,select 命令不会自动退出,而是等待用户继续选择,须要执行 break 命令来退出,也能够按 CTRL-D 来输入EOF进行退出。输入EOF退出后,name 变量值会保持以前的值不变,不会被自动清空。

select 命令的内部语句里面,能够用 exit 命令来直接退出整个脚本的执行,从而退出 select 的选择。若是是在函数内调用 select 命令,则能够用 return 命令来直接退出整个函数,从而退出 select 的选择。

select 命令实例

假设有一个 testselect.sh 脚本,内容以下:

#!/bin/bash

select animal in lion tiger panda flower; do
    if [ "$animal" = "flower" ]; then
        echo "Flower is not animal."
        break
    else
        echo "Choose animal is: $animal"
    fi
done

echo "++++ Enter new select ++++"
select animal in "lion tiger panda"; do
    echo "Your choose is: $animal"
    break
done

这个脚本的第一个 select 命令定义了四个菜单项:liontigerpandaflower,若是用户选择了 flower 则执行 break 命令退出 select 的选择,不然会打印出用户选择的动物名。

第二个 select 命令用双引号把菜单选项括起来,以便查看加了双引号后的效果。

执行该脚本,输出结果以下:

$ ./testselect.sh
1) lion
2) tiger
3) panda
4) flower
#? 1
Choose animal is: lion
#? 2
Choose animal is: tiger
#? 7
Choose animal is:
#? lion
Choose animal is:
#? 4
Flower is not animal.
++++ Enter new select ++++
1) lion tiger panda
#? 1
Your choose is: lion tiger panda

能够看到,select 命令要经过菜单项前面的数字来选择对应的项,并把对应项的名称赋值给指定的 animal 变量。

输入菜单项自己的字符串并不能选择这个菜单项。输入无效的菜单项编号不会报错。这两种状况都会把 animal 变量值清空。

自定义提示信息

上面的 #? 是 bash 的 PS3 提示符,咱们能够为 PS3 变量赋值,再执行 select 命令,从而打印自定义的提示信息。举例以下:

$ PS3="Enjoy your choose:> "
$ select animal in lion tiger; do echo "Choose: $animal"; break; done
1) lion
2) tiger
Enjoy your choose:> 1
Choose: lion

能够看到,为 PS3 变量赋值后,select 命令会打印所赋值的内容,做为提示符。

修改菜单项的分割字符

咱们能够修改 bash 的 IFS 变量值,指定不一样菜单项之间的分割字符,但在使用上有一个注意事项,具体说明以下:

$ IFS=/
$ animal_list="big lion/small tiger"
$ select animal in $animal_list; do echo "Choose: $animal"; break; done
1) big lion
2) small tiger
#? 1
Choose: big lion
$ select animal in big lion/small tiger; do echo "Choose: $animal"; break; done
1) big
2) lion/small
3) tiger
#? 2
Choose: lion/small

上面的例子把 IFS 赋值为 /,而后定义 animal_list 变量,用 / 隔开了 big lionsmall tiger 两项,用 select 命令从 animal_list 变量获取菜单选项时,能够看到再也不用空格来隔开选项,而是用 IFS 赋值后的 / 来隔开选项。

可是,当 select 命令不从 animal_list 变量获取菜单选项,而是直接写为 select animal in big lion/small tiger 命令时,它仍是用空格来隔开选项,而不是用 IFS 赋值后的 / 来隔开选项。

缘由在于,IFS 用于 bash 扩展后的单词拆分,使用 $animal_list 获取 animal_list 变量值就是一种扩展,从而发生单词拆分,用 IFS 的值来拆分红几个单词。

直接写为 in big lion/small tiger 没有发生扩展,因此没有使用 IFS 来拆分单词。

查看 man bash 对 IFS 的说明以下:

IFS
The Internal Field Separator that is used for word splitting after expansion and to split lines into words with the read builtin command. The default value is ``<space><tab><newline>''.

翻译成中文就是,IFS (Internal Field Separator) 用于在扩展后进行单词拆分,并使用 read 内置命令将行拆分为单词。

即,要在扩展以后,才会用 IFS 的值来拆分单词。

在经过 IFS 修改 select 命令的菜单项分割字符时,菜单列表须要保存到变量里面,而后在 select 命令里面获取该变量值,进行变量扩展,IFS 才会生效

相关文章
相关标签/搜索