Shell脚本
到达了这里,那就是对前面的内容进行了系统学习后,可以开始接触较为简单的脚本执行了。
脚本实际上就是命令的集合,和我们人工去处理Linux系统的基础环境没啥区别。但如果你要部署上百台机器时,那脚本就是一个很好的选择了。
脚本最大的缺点是需要对执行时的正确与否进行判断,不然容易出现某步出错但继续往下走的情况,容易导致环境出问题。在虚拟机上我们可以对环境进行镜像来还原避免,可在实际生产环境中会导致另一个问题:镜像和回滚都需要大量的时间,同时需要大量的存储空间。在商业中存储空间也是钱,老板不太可能给你包这么大的底,所以使用脚本时一定要注意再注意,先在测试环境保证没问题了再去生产环境进行上线!
注:Linux上的脚本也可以使用python或其它方式实现,但本篇专注于Shell脚本
编程基础
Talk is cheap,show me the code --Linus
编写脚本时其实也类似于C、Java、Python等编程语言一样,有一定的共通之处。但在排查问题和询问他人时一定要少描述,将代码和报错给到他人。这样会减少大家的沟通成本,同时大家也能更加融洽的讨论真正的问题而不是在描述上纠结。
Shell 脚本语言的基本用法
shell 脚本的用途
- 将简单的命令组合完成复杂的工作,自动化执行命令,提高工作效率
- 减少手工命令的输入,一定程度上避免人为错误
- 将软件或应用的安装及配置实现标准化
- 用于实现日常性的,重复性的,非交互式的运维工作,如:文件打包压缩备份,监控系统运行状态并实现告警等
shell 脚本基本结构
shell是基于过程式、解释执行的语言(即脚本本身和人为交互执行命令没较大区别)
shell脚本是包含一些命令或声明,并符合一定格式的文本文件。
一个shell脚本文件中主要包含以下内容
- 各种系统命令的组合
- 数据存储:变量、数组
- 表达式:a + b
- 控制语句:if
shell 脚本创建过程
1.用编辑器(vi/vim)创建新文件,首行必须是 shell 声明(shebang)。写完内容后保存退出
2.添加可执行权限(x)
3.运行脚本
格式要求:首行shebang机制
声明有这样几种,我们编写的shell脚本是主要使用#!/bin/bash
#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl
#!/usr/bin/ruby
#!/usr/bin/lua
shell 脚本注释规范
紧随声明机制后面的应该是脚本注释,也就是脚本的作者、创建时间、脚本的功能及作用、版权信息、作者联系方式等
例子
[root@ubuntu2204 ~]# vim test.sh
#!/bin/bash
#
#****************************************************
#Author: 作者名
#QQ: QQ联系方式
#Date: 发布日期
#FileName: 文件名
#URL: 作者的博客或其它网页
#Description: 作用
#Copyright(C): 版权信息
#****************************************************
echo "hello world"
这些内容也可以配置成 vim 自动生成注释
每个用户的家目录下.vimrc里存放这些内容后,当使用vim创建文件时就会自动将满足条件的内容添加进新文件中
[root@ubuntu2204 ~]# vim .vimrc
set nu
set cul
set ts=2
set shiftwidth=2
autocmd BufNewFile *.sh exec ":call SetTitle()"
fun SetTitle()
if expand("%:e") == 'sh'
call setline(1,"#!/bin/bash")
call setline(2,"#")
call setline(3,"#*********************************************************")
call setline(4,"#Author: zhouhao")
call setline(5,"#QQ: 1193306316")
call setline(6,"#Date: ".strftime("%Y-%m-%d"))
call setline(7,"#FileName: ".expand("%"))
call setline(8,"#URL: https://www.zhouhaoit.com")
call setline(9,"#Description: The test script")
call setline(10,"#Copyright: ".strftime("%Y")." All rights reserved")
call setline(11,"#********************************************************")
call setline(12,"")
call setline(13,"")
endif
endfunc
autocmd BufNewFile * normal G
第一个 shell 脚本
和我们学其它编程语言一样,我们一开始会写一个脚本,来向世界问好~
vim hello.sh
#!/bin/bash
echo "Hello, World!"
如何运行它呢?
bash hello.sh
或
. /root/hello.sh
或
chmod +x hello.sh (给执行权限)
/root/hello.sh
. hello.sh(等同于 source hello.sh)
同时也很明显了,shell脚本其实就是一串命令的集合!
脚本如何还是需要自己去多加尝试,这里就不放更多的脚本示例了
变量
变量
变量表示命令的内存空间,将数据放在内存空间中,通过变量名来进行引用,进而获得数据
数据要存在内存空间中,而内存空间又是通过内存地址来访问的,但内存地址一般是16进制的编号
但为了方便使用(谁会记16进制地址名啊),所以就有了变量名。当访问变量时,实际是访问其对应的内存地址的对应内存空间
变量类型
变量类型:
- 内置变量,如:PS1、PATH、UID、HOSTNAME、$$、BASHPID、PPID、$?、HISTSIZE
- 用户自定义变量
不同的变量存放的数据不同,决定了以下
- 数据存储方式
- 参与的运算
- 表示的数据范围
变量数据类型:
- 字符
- 数值:整型、浮点型 (bash 不支持浮点数)
- 布尔
- 指针
- 结构体:自定义的复合类型的数据类型
- …
Shell 中变量命名法则
命名要求
- 区分大小写
- 不能使用程序中的保留字和内置变量:如: if、for
- 只能使用数字、字母及下划线,且不能以数字开头。注意:不支持短横线"-",和主机名相反
命名习惯
- 见名知义,用英文单词命名,并体现出实际作用,不要用简写,如:ATM
- 变量名大写
- 局部变量小写
- 函数名小写
- 大驼峰StudentFirstName,由多个单词组成,且每个单词的首字母是大写,其它小写
- 小驼峰studentFirstName,由多个单词组成,第一个单词的首字母小写,其它部分沿用大驼峰
- 下划线: student_first_name
变量定义和引用
按变量的生效范围等标准划分变量类型
- 普通变量: 生效范围为当前shell进程; 对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效
- 环境变量: 生效范围为当前shell进程及其子进程
- 本地变量: 生效范围为当前shell进程中某代码片段,通常指函数
变量赋值:
name='value'
value可以是多种类型
name='root' #字符串
name="$USER" #变量引用
name=`COMMAND` #命令引用(存入命令的输出)
name=$(COMMAND) #同样也是命令引用
注:变量赋值是临时生效。当退出终端后,变量会自动删除,无法持久化保存。脚本中的变量会随着脚本的结束也自动删除。
变量引用(所有变量统一用法)
$name
${name}
弱引用和强引用
- “$name” 弱引用,其中的变量引用会被替换为变量值
- ‘$name’ 强引用,其中的变量引用不会被替换为变量值,而保持原字符串
环境变量
环境变量:
- 可以使子进程(可以一直往下继承)继承父进程的变量,但是无法让父进程使用子进程的变量
- 一旦子进程修改从父进程继承的变量,将会新的值传递给进程(孙子进程等等)
- 一般只在系统配置文件中使用,在脚本中较少使用
# 声明并赋值
export name=VALUE
declare -x name=VALUE
# 其他方法
name=VALUE
export name
删除变量:
unset name
只读变量
只读变量:只能在声明时定义,后续无法修改和删除。即常量
声明只读变量:
readonly name
declare -r name
查看只读变量
readonly [-p]
declare -r
位置变量
位置变量:在bash shell中内置的变量,在脚本代码中调用通过命令行传递给脚本的参数
$1,$2,... #对应第一个、第二个等参数,shift [n]换位置
$0 #执行脚本时使用的名字。启动时使用的什么名字就显示什么
$* #传递给脚本的所有参数,全部参数 合并 为一个字符串(默认使用空格分隔)
$@ #传递给脚本的所有参数,全部参数为 独立 的字符串(保留原始分隔)
$# #传递给脚本的参数的个数
shift n #删除前n个参数,并将后面的参数向前移(shift 1 删除$1,将$2的值给到$1)
清空所有位置变量
set --
展开命令行
在命令中我们可能会使用了各种通配符。但系统并不认识通配符,所以在执行之前,通配符会被先解析成具体的信息。命令的展开执行顺序如下:
把命令行分成单个命令词
展开别名
展开大括号的声明{}
展开波浪符声明 ~
使用命令替换$() 和 ``
再次把命令行分成命令词
展开文件通配符*、?、[abc]等等
准备I/O重导向<、>
运行命令
如果有时候我们不希望被识别为特殊字符:
\ #使用反斜线,使随后的字符按原意解释
加引号来防止扩展
'' #单引号,里面的内容全部不会展开
"" #也可防止扩展。但当识别到$时例外
变量扩展
`` #反引号。执行其中的命令,使用返回值替换
\ #反斜线。禁止后一个字符的扩展
! #感叹号。后面跟数字后将会替换为历史中的第几条命令
脚本安全和 set
set 命令:可以用来定制 shell 环境
$- 变量
| 选项 | 含义 | 备注 |
|---|---|---|
| h | hashall | 开启hash表缓存外部命令路径 |
| i | interactive-comments | 允许在交互式Shell中使用注释(交互式Shell: 例如我们的远程连接,交互式的执行命令) |
| m | monitor | 开启监控模式,可通过 Job control 来控制进程的停止、继续,后台或者前台执行等 |
| B | braceexpand | 是否支持大括号扩展(即是否能使用{}) |
| H | history | 是否可用! 来展开历史命令 |
echo $- #查看有哪些选项被启用(注:这个变量是+为取消,-为添加)
set +h #取消hash表缓存
set -h #启用hash表缓存
set 命令实现脚本安全
| 字符 | 作用 |
|---|---|
| u | 开启此项,在使用一个没有声明的变量时,会报错,并终止脚本。同 set -o nounset |
| e | 开启此项,命令返回非0时直接退出脚本,不继续执行后面代码。同 set -o errexit |
| o | set -o 显示所有;set -o option 开启 option 项;set +o option 关闭 option 项 |
| x | 执行命令时,打印命令及其参数。同set -x |
-u 在扩展一个没有设置的变量时,显示错误信息,等同 set -o nounset
-e 如果一个命令返回一个非0退出状态值(失败)就退出,等同set -o errexit
-o option 显示,打开或者关闭选项 显示选项:set -o 打开选项:set -o 选项 关闭选项:set +o 选项
-x 当执行命令时,打印命令及其参数,类似 bash -x
格式化输出 printf
相当于增强版的 echo,实现丰富的格式化输出
格式
printf format args...

常用格式替换符
| 替换符 | 功能 |
|---|---|
| %s | 字符串 |
| %d,%i | 十进制整数 |
| %f | 浮点格式 |
| %c | ASCII字符,即显示对应参数的第一个字符 |
| %b | 相对应的参数中包含转义字符时,可以使用此替换符进行替换,对应的转义字符会被转义 |
| $o | 八进制值 |
| %u | 不带正负号的十进制值 |
| %x | 十六进制值(a-f) |
| %X | 十六进制值(A-F) |
| %% | 表示%本身 |
说明:
%[N]s # N表示输出宽度,不够使用空格补齐 -N 表示左对齐
%[0][N]d # 0表示宽度不够时在左边补0,N表示输出宽度
%[.N]f # .N 表示保留的小数位
常用转义字符
| 转义符 | 功能 |
|---|---|
| \a | 警告字符,通常为ASCII的BEL字符 |
| \b | 后退 |
| \f | 换页 |
| \n | 换行 |
| \r | 回车 |
| \t | 水平制表符 |
| \v | 垂直制表符 |
| \ | 表示\本身 |
算术运算
Shell允许在某些情况下对算术表示式进行求值,比如:let和declare 内置命令,(( ))复合命令和算术扩展。求值以固定宽度的整数进行,不检查溢出,尽管除以0 被标记为错误。运算符及其优先级,关联性和值与C语言相同。以下运算符列表分组为等优先级运算符级别。级别按降序排列优先。
注意:bash 只支持整数,不支持小数
** #乘方(指数运算)
* / % #乘法、除法、取余
+ - #加法、减法
<< >> #左移位、右移位(按位)
<= >= < > #比较(小于等于、大于等于、小于、大于)
== != #等于、不等于
& #按位与
^ #按位异或
| #按位或
&& #逻辑与
|| #逻辑或
expr?expr:expr #条件运算符(三元运算)
expr1,expr2 #逗号运算符
= *= /= %= += -= <<= >>= &= ^= |= #赋值及复合赋值
++i --i #变量前置自增、前置自减
i++ i-- #变量后置自增、后置自减
! ~ #逻辑非、按位取反(否定)
Linux的随机数生成器
$RANDOM #取值范围:0-32767
#生成固定范围随机数
echo $[RANDOM%10] #生成0-9的随机数
随机字体颜色
echo -e "\033[1;$[RANDOM%7+31]mhello\033[0m"
#详细的颜色和用法可以前往观看 <命令提示符自定义>
逻辑运算
这部分与数电非常相似。但这里只会用到与逻辑门类似的几个运算符,用于数学计算
与或非

| bool值 | 二进制表示 | 说明 |
|---|---|---|
| true | 1 | 真 |
| false | 0 | 假 |
与(&):有一假则全假,全真才是真
# 在Linux中的数学计算中使用时,是以二进制形式来进行的比较
echo $((5 & 3)) # 5 的二进制是 101,3 是 011 → 按位与结果为 001 (十进制 1)
echo $((7 & 0)) # 任何数与 0 按位与结果均为 0
echo $((1 & 1)) # 1 的二进制是 1 → 按位与结果仍为 1
或(|):当两者有一个为真时,则结果为真
echo $((5 | 3)) # 5 的二进制是 101,3 是 011 → 按位或结果为 111 (十进制 7)
echo $((1 | 0)) # 1 的二进制是 1,0 是 0 → 按位或结果为 1
echo $((0 | 0)) # 结果为 0
非(!):当输入为假输出为真,输入为真时则输出为假
| 变量 | 运算 | 非运算结果 |
|---|---|---|
| 0 | ! 1 | 0 |
| 1 | ! 0 | 1 |
异或(^):输入的两个值不同是为真,相同时为假
| 变量1 | 变量2 | 异或运算 | 异或运算结果 |
|---|---|---|---|
| 0 | 0 | 0^0 | 0 |
| 0 | 1 | 0^1 | 1 |
| 1 | 0 | 1^0 | 1 |
| 1 | 1 | 1^1 | 0 |
短路运算
用于链接命令。上一条命令结果为(假/真)时,选择性执行后面的命令
短路与(&&)
| command1值 | command2值 | 短路与运算 | 短路与运算结果($?) |
|---|---|---|---|
| true | true | cmd1 && cmd2 | true |
| true | false | cmd1 && cmd2 | false |
| false | (被跳过) | cmd1 && cmd2 | false |
只有cmd1成功时,才会执行后面的命令。但不会管后面命令执行成功与否
短路或(||)
| command1值 | command2值 | 短路或运算 | 短路或运算结果($?) |
|---|---|---|---|
| true | (被跳过) | cmd1 || cmd2 | true |
| false | true | cmd1 || cmd2 | true |
| false | false | cmd1 || cmd2 | false |
当cmd1执行失败时,执行后面的cmd2
注:Shell中的($?)是用于存储上一条命令执行是否成功。当命令成功是则为0,命令失败时为1-255中任意一个数。具体报错数字得看命令中的定义
条件测试命令
条件测试:
用于判断某需求是否满足,就需要使用测试机制来检查。专用的测试表达式需要有测试命令进行辅助。便于与条件判断等方法组合实现自动化。
若真,则状态码变量**$?**返回0
若假,则状态码变量**$?**返回1
表达式条件测试
# 条件测试命令
[ 判断语句 ]
[[ 增强版,支持扩展正则表达式 ]]
# 注:方括号两侧与其中的判断语句必须有空格分隔,不然会报错
文件判断相关
-a FILE #如果文件存在则为真
-b FILE #如果文件为块特殊文件则为真
-c FILE #如果文件为字符特殊文件则为真
-d FILE #如果文件为目录则为真
-e FILE #如果文件存在则为真
-f FILE #如果文件存在且为常规文件则为真
-g FILE #如果文件的组属性设置打开则为真
-h FILE #如果文件为符号链接则为真
-L FILE #如果文件为符号链接则为真
-k FILE #如果文件的粘滞 (sticky) 位设定则为真
-p FILE #如果文件为命名管道则为真
-r FILE #如果当前用户对文件有可读权限为真
-s FILE #如果文件存在且不为空则为真
-S FILE #如果文件是套接字则为真
-t FD #如果文件描述符在一个终端上打开则为真
-u FILE #如果文件设置了SUID特殊权限则为真
-w FILE #如果当前用户对文件有可写权限为真
-x FILE #如果当前用户对文件有可执行权限为真
-O FILE #如果当前用户是文件属主为真
-G FILE #如果当前用户对文件属组为真
-N FILE #如果文件上次被读取之后修改过则为真
FILE1 -nt FILE2 #如果 file1 文件新于 file2 文件 则为真(根据修改日期)
FILE1 -ot FILE2 #如果 file1 文件旧于 file2 文件则为真
FILE1 -ef FILE2 #如果 file1 文件是 file2 文件的硬链接则为真
字符串判断相关
-z STRING #判断字符串是否为空,为空则为真
-n STRING #如果字符串不为空则为真
STRING #同上
#两个字符串变量比较,一定要有空格,如果没有空格,就变成赋值了
STRING1 = STRING2 #如果 string1 和 string2 字符串相同则为真
STRING1 != STRING2 #如果 string1 和 string2 字符串不相同则为真
STRING1 < STRING2 #只比较第一个字符,以字母表顺序来比较,string1在string2 之前则为真,< 要转义
STRING1 > STRING2 #只比较第一个字符,以字母表顺序来比较,string1在string2 之后则为真, > 要转义
数学相关
#数字相关 格式 arg1 OP arg2
-eq #等于
-ne #不等于
-lt #小于
-le #小于等于
-gt #大于
-ge #大于等于
#算术表达式比较
== #相等
!= #不相等
<= #小于或等于
>= #大于或等于
< #小于
> #大于
其它
-o OPTION #如果在shell 中开启了某项,则为真
-v VAR #如果变量被设置为真
-R VAR #如果变量被设置且被引用则为真
! EXPR #表达式结果取反
EXPR1 -a EXPR2 #如果 expr1 和 expr2 都为真则为真 &&
EXPR1 -o EXPR2 #如果 expr1 和 expr2 有一个为真则为真
关于()和{}
( cmd1;cmd2;... ) 和 { cmd1;cmd2;...; } 都可以将多个命令组合在一起,批量执行
( list ) 会开启子shell,并且list中变量赋值及内部命令执行后,将不再影响后续的环境
{ list; } 不会开启子shell, 在当前shell中运行,会影响当前shell环境,左侧要有空格,右侧要有; 结束
组合测试条件
很多时候我们需要一次多个条件一起判断。不然会导致脚本中出现多层嵌套结构,降低代码的可读性,所以此时我们可以使用复合判断语句来进行判断。
第一种方式
# 使用-a , ! 和 -o 来进行连接
[ EXPRESSION1 -a EXPRESSION2 ] #并且,EXPRESSION1和EXPRESSION2都是真,结果才为真
[ EXPRESSION1 -o EXPRESSION2 ] #或者,EXPRESSION1和EXPRESSION2只要有一个真,结果就为真
[ ! EXPRESSION ] #取反
第二种方式
# 使用 && , ! , || 来进行连接
COMMAND1 && COMMAND2 #并且,短路与,代表条件性的AND THEN
#如果COMMAND1成功,将执行COMMAND2,否则,将不执行COMMAND2
COMMAND1 || COMMAND2 #或者,短路或,代表条件性的OR ELSE
#如果COMMAND1 成功,将不执行COMMAND2,否则,将执行COMMAND2
! COMMAND #非,取反
使用read来接受输入
使用read来把输入值分配给一个或多个shell变量,read从标准输入中读取值,给每个单词分配一个变量,所有剩余单词都被分配给最后一个变量,如果变量名没有指定,默认标准输入的值赋值给系统内置变量REPLY。
read [options] [name ...]
#常见选项
-p #指定要显示的提示
-s #静默输入,一般用于密码
-n N #指定输入的字符长度N
-d 'CHAR' #输入结束符
-t N #TIMEOUT为N秒
Bash shell 的配置文件
bash shell的配置文件很多,可以根据范围来划分为以下两类:
全局配置:针对所有用户都有效的配置。但会被个人配置覆盖。(先加载全局配置再加载个人配置)
# 文件所在地
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc ------------------------ /etc/bash.bashrc #ubuntu
个人配置:只在特定用户登录时生效。
~/.bash_profile
~/.bashrc
编辑配置文件生效
对profile和bashrc文件修改后,想使修改内容立刻生效需要一定的操作
- 关闭当前shell进程重新启动一个
- source path 使用该指令重新加载指定路径(path)的配置文件
流程控制
条件选择
选择执行 if 语句
# 格式
if COMMANDS; then
COMMANDS;
elif COMMANDS; then
COMMANDS; ...
else
COMMANDS;
fi
# 其中if必须存在。elif可以存在多个。else至多存在一个
- 多个条件时,逐个条件进行判断,第一次遇为“真”条件时,执行其分支,而后结束整个if语句
- if 语句可嵌套
条件判断 case 语句
# 格式
case 变量引用 in
PAT1)
分支1命令
;;
PAT2)
分支2命令
;;
...
*)
其它分支命令
;;
esac
# 例:
read -p "Do you agree(yes/no)? " INPUT
INPUT=`echo $INPUT | tr 'A-Z' 'a-z'`
case $INPUT in
y|yes)
echo "You input is YES"
;;
n|no)
echo "You input is NO"
;;
*)
echo "Input fales,please input yes or no!"
;;
esac
循环
将某代码段重复运行多次,通过满足进入循环的条件和退出循环的条件来达成任务
循环 for
# 格式
for NAME [in WORDS ... ] ; do COMMANDS; done
#方式1
for 变量名 in 列表;do
循环体
done
#方式2
for 变量名 in 列表
do
循环体
done
运行方式:
- 依次将列表中的元素赋值给“变量名”; 每次赋值后即执行一次循环体; 直到列表中的元素耗尽,循环结束
- 如果省略 [in WORDS … ] ,此时使用位置参数变量 in “$@”
for 循环列表生成方式:
- 直接给出列表
- 整数列表:如 {start…end}
- 返回列表的命令:如 $(COMMAND)
- 使用glob,如:*.sh
- 变量引用,如:$@,$,$#
循环 while
# 格式
while CONDITION; do COMMANDS; done
while CONDITION; do
循环体
done
while CONDITION
do
循环体
done
说明:
CONDITION:循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;条件为“true”,则执行一次循环;直到条件测试状态为“false”终止循环,因此:
CONDTION一般应该有循环控制变量;而此变量的值会在循环体不断地被修正
进入条件:CONDITION为 true
退出条件:CONDITION为 false
注:while 存在特殊用法
while read line; do
循环体
done < /PATH/FROM/SOMEFILE
依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line
循环 until
# 格式
until CONDITION; do COMMANDS; done
until CONDITION; do
循环体
done
说明:
进入条件: CONDITION 为false
退出条件: CONDITION 为true
循环控制语句 continue
continue: 是跳过当前循环的剩余部分,直接进入下一次迭代
continue [N]:跳过从内向外数第N层循环的本次迭代
continue 2: 跳过外层循环的本次迭代(不带嵌套循环里会出错)
# 格式
while CONDITION1; do
CMD1
...
if CONDITION2; then
continue
fi
CMDn
...
done
循环控制语句 break
break [N]:提前结束第N层整个循环,最内层为第1层
# 格式
while CONDITION1; do
CMD1
...
if CONDITION2; then
break
fi
CMDn
...
done
循环控制 shift
shift [n] 用于将参量列表 list 左移指定次数,缺省为左移一次。
参量列表 list 一旦被移动,最左端的那个参数就从列表中删除。while 循环遍历位置参量列表时,常用到shift
# 例子
[root@ubuntu2204 ~]# cat shift.sh
until [ -z "$1" ]; do
echo "$@ "
shift
done
[root@ubuntu2204 ~]# bash s.sh a b c d e f g
a b c d e f g
b c d e f g
c d e f g
d e f g
e f g
f g
g
循环与菜单 select
# 格式
select NAME [in WORDS ... ;] do COMMANDS; done
select NAME in list ;do
循环体命令
done
说明:
- select 循环主要用于创建菜单,按数字顺序排列的菜单项显示在标准输出上,并显示 PS3 提示符,等待用户输入
- 用户输入菜单列表中的某个数字,执行相应的命令
- 用户输入菜单列表中的某个数字,会将对应的WORD值赋值给NAME变量
- 用户输入被保存在内置变量 REPLY 中
- select 是个无限循环,因此要写一个选项是使用 break 命令退出循环,或用 exit 命令终止脚本。也可以按 ctrl+c 退出循环
- select 经常和 case 联合使用
- 与 for 循环类似,可以省略 in list,此时使用位置参量
函数
函数介绍
函数是指由若干条shell命令组成的语句块,实现代码重用和模块化编程
它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部分
函数和shell程序区别
- Shell程序在子Shell中运行
- 函数在当前Shell中运行。因此在当前Shell中,函数可对shell中变量进行修改
管理函数
函数由两部分组成:函数名和函数体
查看帮助
help function
定义函数
#语法一
func_name(){
...函数体...
}
#语法二
function func_name {
...函数体...
}
#语法三
function func_name(){
...函数体...
}
查看函数
#查看当前已定义的函数名(只查看函数名)
declare -F
#查看当前已定义的函数定义(查看函数名和函数内部的命令)
declare -f
#查看指定当前已定义的函数名
declare -f func_name
#查看当前已定义的函数名定义
declare -F func_name
删除函数
unset func_name
函数调用
函数的调用方式
- 可在交互式环境下定义函数
- 可将函数放在脚本文件中作为它的一部分
- 可放在只包含函数的单独文件中
调用:函数只有被调用才会执行,通过给定函数名调用函数,函数名出现的地方,会被自动替换为函数代码
函数的生命周期:被调用时创建,返回时终止