Linux shell编程学习笔记21:用select in循环语句打造菜单

一、select in循环语句的功能

Linux shell脚本编程提供了select in语句,这是 Shell 独有的一种循环语句,非常适合终端(Terminal)这样的交互场景,它可以根据用户的设置显示出带编号的菜单,用户通过输入不同的编号就可以选择不同的菜单,并执行与菜单对应的功能,这是C、C++、Java、Python 等编程语言中是没有的。

二、select in循环语句的语法格式

select 变量名 in 值1 [值2 ……值n]
do
    语句或命令1
    [……]
    [语句或命令n]
done

在do 和 done之间,我们可以用if或case语句根据变量名的值执行相应语句或命令,实现不同的功能。

三、实例1

我们会询问你喜欢吃哪种水果,并显示4个水果选项:apple、banana、orrange、peach,以及一个退出循环的选项exit

如果你的选择4个水果中的一个,将会显示你选择的水果名称

如果你选择了是exit,将会看到提示bye,并结束循环。

代码如下:

echo "What is your favourite fruit?"
select f in "apple" "banana"  "orrange" "peach" "exit"
do
    if [[ $f == "exit" ]]; then
        echo "bye"
	break
    else
        echo "You have selected $f"
    fi
 done

(一)在zsh中

# csdn @ edu in ~ [22:32:22] 
$ echo "What is your favourite fruit?"; select f in "apple" "banana"  "orrange" "peach" "exit"; do; if [[ $f == "exit" ]]; then echo "bye"; break; else echo "You have selected $f"; fi; done
What is your favourite fruit?
1) apple    2) banana   3) orrange  4) peach    5) exit     
?# 1
You have selected apple
?# 4
You have selected peach
?# 5
bye

# csdn @ edu in ~ [22:32:52] 

Linux shell编程学习笔记21:用select in循环语句打造菜单_第1张图片

我们可以看到zsh 根据select in循环语句提供的值显示出了五个菜单项:

1) apple    2) banana   3) orrange  4) peach    5) exit     

每个菜单项前有1个数字。

然后显示提示符 ?# 让我们输入菜单项前的数字来选择相应的菜单项。

我们先输入了1,所以显示You have selected apple

接着我们输入4,所以显示You have selected peach

最后我们输入5,这是退出循环的选项,于是我们看到了bye,并退回到了命令行状态。

(二)在bash中

# csdn @ edu in ~ [22:46:42] 
$ bash
[csdn ~]$ echo "What is your favourite fruit?"; select f in "apple" "banana"  "orrange" "peach" "exit"; do; if [[ $f == "exit" ]]; then echo "bye"; break; else echo "You have selected $f"; fi; done
bash: syntax error near unexpected token `;'
[csdn ~]$ echo "What is your favourite fruit?"; select f in "apple" "banana"  "orrange" "peach" "exit"; do if [[ $f == "exit" ]]; then echo "bye"; break; else echo "You have selected $f"; fi; done
What is your favourite fruit?
1) apple
2) banana
3) orrange
4) peach
5) exit
#? 1 
You have selected apple
#? 3
You have selected orrange
#? 5
bye
[csdn ~]$ 

Linux shell编程学习笔记21:用select in循环语句打造菜单_第2张图片

我们可以看到bash 和zsh 对脚本的支持不太一样。

刚才在zsh中执行正常的脚本,在bash中执行时出错:

bash: syntax error near unexpected token `;'

我们把 do 语句后面的; 去掉后,脚本可以执行了。

根据select in循环语句提供的值显示出了五个菜单项:

我们可以看到bash 像zsh 一样,根据select in循环语句提供的值显示出了五个菜单项:

1) apple
2) banana
3) orrange
4) peach
5) exit 

每个菜单项前有1个数字。

但与zsh的横向显示方式不同,bash采用的是纵向显示方式。

然后显示提示符#?  让我们输入菜单项前的数字来选择相应的菜单项。

bash的这个提示符#?  跟zsh显示的提示符字符顺序是相反的,zsh显示的提示符字符是?#

我们先输入了1,所以显示You have selected apple

接着我们输入3,所以显示You have selected orrange

最后我们输入5,这是退出循环的选项,于是我们看到了bye,并退回到了命令行状态。

四、容错机制测试

在上面的实例1中,如果我们输入的字符不属于菜单项前的数字,代码会怎么执行呢?

(一)在zsh中

# csdn @ edu in ~ [23:03:43] 
$ echo "What is your favourite fruit?"; select f in "apple" "banana"  "orrange" "peach" "exit"; do; if [[ $f == "exit" ]]; then echo "bye"; break; else echo "You have selected $f"; fi; done
What is your favourite fruit?

1) apple    2) banana   3) orrange  4) peach    5) exit     
?# a
You have selected 
?# 6
You have selected 
?# 3
You have selected orrange
?# 5 
bye

# csdn @ edu in ~ [23:04:12] 

Linux shell编程学习笔记21:用select in循环语句打造菜单_第3张图片

 (二)在bash中

# csdn @ edu in ~ [23:04:12] 
$ exec bash
[csdn ~]$ echo "What is your favourite fruit?"; select f in "apple" "banana"  "orrange" "peach" "exit"; do; if [[ $f == "exit" ]]; then echo "bye"; break; else echo "You have selected $f"; fi; done
bash: syntax error near unexpected token `;'
[csdn ~]$ echo "What is your favourite fruit?"; select f in "apple" "banana"  "orrange" "peach" "exit"; do if [[ $f == "exit" ]]; then echo "bye"; break; else echo "You have selected $f"; fi; done
What is your favourite fruit?
1) apple
2) banana
3) orrange
4) peach
5) exit
#? b
You have selected 
#? 9
You have selected 
#? 3
You have selected orrange
#? 5
bye
[csdn ~]$ 

Linux shell编程学习笔记21:用select in循环语句打造菜单_第4张图片 可以看到,不管zsh还是bash,如果我们输入的字符不属于菜单项前的数字,shell并不会进行干预,代码仍然会执行,并由if语句根据$f的值进行处理。

所以为了实现预期的效果,我们需要自己对用户输入的字符的有效性进行检查和处理。

五、如果 传递给 select in 的值超过9个会怎么显示?(实例2)

我们通过下面的代码,给select in 传递了36个值来测试。

(一) 在 zsh中

# csdn @ edu in ~ [23:14:29] 
$ echo "What is your favourite fruit?"; select f in 1 2 3 4 5 6 7 8  9 a  b c d e f g h i j  k l m n o p q r s t u v w x y z exit; do; if [[ $f == "exit" ]]; then echo "bye"; break; else echo "
You have selected $f"; fi; done
What is your favourite fruit?
1) 1      3) 3      5) 5      7) 7      9) 9      11) b     13) d     15) f     17) h     19) j     21) l     23) n     25) p     27) r     29) t     31) v     33) x     35) z     
2) 2      4) 4      6) 6      8) 8      10) a     12) c     14) e     16) g     18) i     20) k     22) m     24) o     26) q     28) s     30) u     32) w     34) y     36) exit  
?# 1
You have selected 1
?# 18
You have selected i
?# m
You have selected 
?# 36
bye

# csdn @ edu in ~ [23:15:12] 

 Linux shell编程学习笔记21:用select in循环语句打造菜单_第5张图片

 这次在zsh也是采用纵向多列的方式来显示菜单。 

(二)在bash中

# csdn @ edu in ~ [23:15:12] 
$ exec bash
[csdn ~]$ echo "What is your favourite fruit?"; select f in 1 2 3 4 5 6 7 8  9 a  b c d e f g h i j  k l m n o p q r s t u v w x y z exit; do if [[ $f == "exit" ]]; then echo "bye"; break; else echo "You have selected $f"; fi; done
What is your favourite fruit?
1) 1       3) 3      5) 5      7) 7      9) 9     11) b     13) d     15) f     17) h     19) j     21) l     23) n     25) p     27) r     29) t     31) v     33) x     35) z
2) 2       4) 4      6) 6      8) 8     10) a     12) c     14) e     16) g     18) i     20) k     22) m     24) o     26) q     28) s     30) u     32) w     34) y     36) exit
#? 9
You have selected 9
#? 20
You have selected k
#? k
You have selected 
#? 36
bye
[csdn ~]$ 

 Linux shell编程学习笔记21:用select in循环语句打造菜单_第6张图片

 这次bash显示菜单的方式与zsh一致。

可以看到,当传递给 select in 的值超过9个时,不管zsh还是bash会以10、11……这种方式给值赋予菜单值。

六、利用数组构建容错机制

(一)实例3

我们可以先将要传递给select in 的值定义并存储到一个数组a中,

再把数组a传递给 select in,

当用户输入数值后,对用户输入的数值进行判断:

  1. 如果用户输入的值 > 数组a的长度 或者 用户输入的值 < 1,那么就显示 bye并退出循环
  2. 否则显示用户选择的fruit。

# csdn @ edu in ~ [23:48:42] 
$ a=(apple banana orrange peach);echo "What is your favourite fruit?"; select f in $a; do; if [[ $f -gt ${#a[*]} ]] || [[ $f < 1 ]]; then echo "bye"; break; else echo "You have selected $f"; fi; done
What is your favourite fruit?
1) apple    2) banana   3) orrange  4) peach    
?# 1
You have selected apple
?# 4
You have selected peach
?# 0
bye

# csdn @ edu in ~ [23:48:52] 

Linux shell编程学习笔记21:用select in循环语句打造菜单_第7张图片

(二)注意

对于 if [[ $f -gt ${#a[*]} ]] || [[ $f < 1 ]] 

1.如果 将  $f -gt ${#a[*]} 写成 $f > ${#a[*]},代码执行就会出现问题

$f > ${#a[*]}

$ a=(apple banana orrange peach);echo "What is your favourite fruit?"; select f in $a; do; if [[ $f > ${#a[*]} ]] || [[ $f < 1 ]]; then echo "bye"; break; else echo "You have selected $f"; fi; done
What is your favourite fruit?
1) apple    2) banana   3) orrange  4) peach    
?# 1
bye

# csdn @ edu in ~ [23:13:38] 

Linux shell编程学习笔记21:用select in循环语句打造菜单_第8张图片

即使我们输入1,代码也会显示bye并跳出循环返回命令行。

这是因为$f 和 ${#a[*]} 在这里进行的是字符串比较。

2.如果将 $f < 1 写为 $f -lt 1,代码执行也会出现问题

# csdn @ edu in ~ [23:48:31] 
$ a=(apple banana orrange peach);echo "What is your favourite fruit?"; select f in $a; do; if [[ $f -gt ${#a[*]} ]] || [[ $f -lt 1 ]]; then echo "bye"; break; else echo "You have selected $f"; fi; done 
What is your favourite fruit?
1) apple    2) banana   3) orrange  4) peach    
?# 1
bye

同样,我们输入1,代码也会显示bye并跳出循环返回命令行。

这是因为$f 和1在进行的是数值比较。

七、如果没有设置退出值(菜单项),如何退出循环?

在上面的实例1和实例2中,我们都设置了exit值给用户选择退出循环,如果我们在脚本中没有作这方面的设置,用户该如何退出循环呢?

有两种方法:

Ctrl+C

Ctrl+D

(一)以bash中用Ctrl+C

# csdn @ edu in ~ [23:26:14] 
$ exec bash
[csdn ~]$ echo "What is your favourite fruit?"; select f in "apple" "banana"  "orrange" "peach" "exit"; do; if [[ $f == "exit" ]]; then echo "bye"; break; else echo "You have selected $f"; fi; done
bash: syntax error near unexpected token `;'
[csdn ~]$ echo "What is your favourite fruit?"; select f in "apple" "banana"  "orrange" "peach" "exit"; do if [[ $f == "exit" ]]; then echo "bye"; break; else echo "You have selected $f"; fi; done
What is your favourite fruit?
1) apple
2) banana
3) orrange
4) peach
5) exit
#? 3
You have selected orrange
#? ^C

Linux shell编程学习笔记21:用select in循环语句打造菜单_第9张图片

按Ctrl+C退出,屏幕上会显示^C。

(二)以bash中用Ctrl+D

[csdn ~]$ echo "What is your favourite fruit?"; select f in "apple" "banana"  "orrange" "peach" "exit"; do if [[ $f == "exit" ]]; then echo "bye"; break; else echo "You have selected $f"; fi; done
What is your favourite fruit?
1) apple
2) banana
3) orrange
4) peach
5) exit
#? 1
You have selected apple
#? 
[csdn ~]$ 

Linux shell编程学习笔记21:用select in循环语句打造菜单_第10张图片

按Ctrl+D退出,屏幕上不会显示出来,更美观一些。 

八、与 case...esac语句配合使用

当我们需要对多个数值分别做不同的处置时,用if语句太麻烦了,我们可以使用case...esca语句配合使用。

我们将实例1修改如下:

a=(apple banana orrange peach)
echo "What is your favourite fruit?"
select f in ${a[*]}
do
   case $f in
     apple) echo 1 apple;;
     banana) echo 2 banana;;
     orrange) echo 3 orrange;;
     peach) echo 4 peach;;
     *) echo bye
        break;;
   esac
done

使用case...esca语句来对用户选择的fruit进行分别处理,如果用户输入的值不在数组a中,将显示bye并退出循环。

(一)在zsh中顺利执行

# csdn @ edu in ~ [22:37:41] 
$ a=(apple banana orrange peach);echo "What is your favourite fruit?"; select f in $a; do; case $f in; apple) echo 1 apple;; banana) echo 2 banana;; orrange)
 echo 3 orrange;;peach) echo 4 peach;; *)echo bye;  break; esac; done

What is your favourite fruit?
1) apple    2) banana   3) orrange  4) peach    
?# 1
1 apple
?# 4
4 peach
?# 5
bye

# csdn @ edu in ~ [22:37:53] 

Linux shell编程学习笔记21:用select in循环语句打造菜单_第11张图片

(二)在bash中

1.命令行执行出错

[csdn ~]$ a=(apple banana orrange peach);echo "What is your favourite fruit?"; select f in $a; do; case $f in; apple) echo 1 apple;; banana) echo 2 banana;; orrange) echo 3 orrange;;peach) echo 4 peach;; *)echo bye;  break; esac; done
bash: syntax error near unexpected token `;'
[csdn ~]$ a=(apple banana orrange peach);echo "What is your favourite fruit?"; select f in $a; do case $f in; apple) echo 1 apple;; banana) echo 2 banana;; orrange) echo 3 orrange;;peach) echo 4 peach;; *)echo bye;  break; esac; done
bash: syntax error near unexpected token `;'
[csdn ~]$ 

bash对;的处理 

 2.创建脚本文件来测试

(1)创建脚本文件a.sh

[csdn ~]$ echo 'a=(apple banana orrange peach)' > a.sh
[csdn ~]$ echo 'echo "What is your favourite fruit?"' >> a.sh
[csdn ~]$ echo 'select f in ${a[*]}' >> a.sh
[csdn ~]$ echo do >> a.sh
[csdn ~]$ echo 'case $f in' >> a.sh
[csdn ~]$ echo 'apple) echo 1 apple;;' >> a.sh
[csdn ~]$ echo 'banana) echo 2 banana;;' >> a.sh
[csdn ~]$ echo 'orrange) echo 3 orrange;;' >> a.sh
[csdn ~]$ echo 'peach) echo 4 peach;;' >> a.sh
[csdn ~]$ echo '*) echo bye' >> a.sh
[csdn ~]$ echo 'break;;' >> a.sh
[csdn ~]$ echo esac >> a.sh
[csdn ~]$ echo done >> a.sh
[csdn ~]$ 

\Linux shell编程学习笔记21:用select in循环语句打造菜单_第12张图片

(2)查看脚本文件a.sh的内容

[csdn ~]$ cat a.sh
a=(apple banana orrange peach)
echo "What is your favourite fruit?"
select f in ${a[*]}
do
case $f in
apple) echo 1 apple;;
banana) echo 2 banana;;
orrange) echo 3 orrange;;
peach) echo 4 peach;;
*) echo bye
break;;
esac
done
[csdn ~]$ 

Linux shell编程学习笔记21:用select in循环语句打造菜单_第13张图片

(3)执行脚本文件a.sh

[csdn ~]$ . a.sh
What is your favourite fruit?
1) apple
2) banana
3) orrange
4) peach
#? 1
1 apple
#? 3
3 orrange
#? 5
bye
[csdn ~]$ 

Linux shell编程学习笔记21:用select in循环语句打造菜单_第14张图片

注意:

对于数组a=(apple banana orrange peach)'

  • 在zsh中,只需要使用$a 就可以获得所有元素的值
  • 在bash中,使用$a 只能获得第1个元素的值,要获得所有元素的值,需要使用${a[*]}或${a[@]}

 

你可能感兴趣的:(Linux世界,麒麟操作系统,系统安全,linux,学习笔记,linux,shell,脚本编程,select,in语句,菜单项,select,in,循环)