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"
doif [[ $f == "exit" ]]; thenecho "bye"breakelseecho "You have selected $f"fidone

(一)在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] 

我们可以看到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 ~]$ 

我们可以看到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] 

 (二)在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 ~]$ 

 可以看到,不管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] 

 

 这次在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 ~]$ 

 

 这次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] 

(二)注意

对于 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] 

即使我们输入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

按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 ~]$ 

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

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

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

我们将实例1修改如下:

a=(apple banana orrange peach)
echo "What is your favourite fruit?"
select f in ${a[*]}
docase $f inapple) echo 1 apple;;banana) echo 2 banana;;orrange) echo 3 orrange;;peach) echo 4 peach;;*) echo byebreak;;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] 

(二)在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 ~]$ 

\

(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 ~]$ 

(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 ~]$ 

注意:

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

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

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/160656.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

专访HuggingFace CTO:开源崛起、创业故事和AI民主化丨智源独家

导读 HuggingFace CTO Julien Chaumond认为&#xff0c;在大模型时代&#xff0c;AI民主化至关重要。随着大语言模型和复杂人工智能系统的崛起&#xff0c;持续提升AI技术的可及性有助于确保这些技术的获取和控制不集中在少数强大实体手中。技术民主化促进了机会均等&#xff0…

【Redis】Redis在Linux与windows上的安装基本操作语法

一、Redis简介 Redis 是完全开源免费的&#xff0c;遵守BSD协议&#xff0c;是一个高性能的key-value数据库。 Redis 与其他 key - value 缓存产品有以下三个特点&#xff1a; Redis支持数据的持久化&#xff0c;可以将内存中的数据保持在磁盘中&#xff0c;重启的时候可以再…

如何设置OBS虚拟摄像头给钉钉视频会议使用

环境&#xff1a; OBS Studio 29.1.3 Win10 专业版 钉钉7.1.0 问题描述&#xff1a; 如何设置OBS虚拟摄像头给钉钉视频会议使用 解决方案&#xff1a; 1.打开OBS 底下来源这添加视频采集设备 选择OBS虚拟摄像头 2.源那再建一个图像&#xff0c;随便选一张图片 3.点击虚…

与AI对话的艺术:如何优化Prompt以获得更好的响应反馈

前言 在当今数字化时代&#xff0c;人工智能系统已经成为我们生活的一部分。我们可以在智能助手、聊天机器人、搜索引擎等各种场合与AI进行对话。然而&#xff0c;要获得有益的回应&#xff0c;我们需要学会与AI进行有效的沟通&#xff0c;这就涉及到如何编写好的Prompt。 与…

【论文导读】-Vertically Federated Graph Neural Network for Privacy-Preserving Node Classification纵向联邦图神经网络

文章目录 论文信息摘要主要贡献vertically federated GNN (VFGNN)执行过程1. 生成初始节点嵌入2. 生成局部节点嵌入3. 生成全局节点嵌入4. 采用DP增强隐私 论文信息 原文地址&#xff1a;https://www.ijcai.org/proceedings/2022/0272.pdf 摘要 Graph Neural Network (GNN) has…

MySQL复习总结(一):基础篇

文章目录 一、MySQL概述二、SQL语句2.1 SQL分类2.2 DDL语言2.2.1 数据库操作2.2.2 表操作:通用2.2.3 表操作:修改2.2.4 表操作:删除 2.3 DML语言2.3.1 添加数据2.3.2 修改数据2.3.3 删除数据 2.4 DQL语言2.5 DCL语言 三、函数四、约束五、多表查询5.1 多表关系 六、事务6.1 事务…

Draft-P802.11be-D3.2协议学习__$9-Frame-Format__$9.3.1.22-Trigger-frame-format

Draft-P802.11be-D3.2协议学习__$9-Frame-Format__$9.3.1.22-Trigger-frame-format 9.3.1.22.1 Genreal9.3.1.22.2 Common Info field9.3.1.22.3 Special User Info field9.3.1.22.4 HE variant User Info field9.3.1.22.5 EHT variant User Info field9.3.1.22.6 Basic Trigge…

迷宫问题的对比实验研究

对不同的迷宫进行算法问题&#xff0c;分别采用栈、队列、基于红黑树的A*算法、以及图论中的最短路径来解决迷宫问题。 基本要求&#xff1a; &#xff08;1&#xff09; 从文件读入9*9的迷宫&#xff0c;设置入口和出口&#xff0c;分别采用以上方法&#xff0c;输出从入口到出…

pytorch+LSTM实现使用单参数预测,以及多参数预测(代码注释版)

开发前准备&#xff1a; 环境管理&#xff1a;Anaconda python: 3.8 显卡&#xff1a;NVIDIA3060 pytorch: 到官网选择conda版本&#xff0c;使用的是CUDA11.8 编译器&#xff1a; PyCharm 简述&#xff1a; 本次使用seaborn库中的flights数据集来做试验&#xff0c;我们通过…

(附源码)基于SSM 车险事故自助理赔小程序-计算机毕设 84607

车险事故自助理赔小程序 摘要 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;车险事故自助理赔小程序被用户普遍…

tolua中table.remove怎么删除表中符合条件的数据

tolua中table.remove怎么删除表中符合条件的数据 介绍问题&#xff08;错误方式删除数据&#xff09;正确删除方案从后向前删除递归方式删除插入新表方式 拓展一下总结 介绍 在lua中删除表中符合条件的数据其实很简单&#xff0c;但是有一个顺序问题&#xff0c;因为lua的表中…

Cygwin一个在 Windows 操作系统上提供类似于Unix、Linux 环境的兼容层项目

一、简介 Cygwin 是一个在 Windows 操作系统上提供类似于 Unix/Linux 环境的兼容层的开源项目。它为 Windows 用户提供了一种在 Windows 平台上运行类 Unix 程序的方式。 Cygwin 提供了一组工具和库&#xff0c;包括一个动态链接库&#xff08;cygwin1.dll&#xff09;和一个用…