2024-08-18 20:06:52 +08:00
|
|
|
|
|
2024-08-18 20:08:23 +08:00
|
|
|
|
# Shell流程控制-函数
|
2024-08-18 20:06:52 +08:00
|
|
|
|
|
|
|
|
|
## 一、Shell 编程之条件结构
|
|
|
|
|
|
|
|
|
|
### 0、走在测试之前--认识各种括号
|
|
|
|
|
|
|
|
|
|
**[]**、()、{}、(())、[[]]、**$(())、$[]、$()、${}**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### 1.单括号[] () {}
|
|
|
|
|
|
|
|
|
|
```txt
|
|
|
|
|
[] test命令的另一种写法
|
|
|
|
|
() 重新开一个子shell然后执行,里面的最后一个命令可以不用分号
|
|
|
|
|
{} 在当前 shell 执行,里面的最后一个命令要用分号,第一个命令和左括号之间必须有一个空格
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
()和{}里的某个命令的重定向只影响该命令, 而括号外的重定向则影响到括号里的所有命令。
|
|
|
|
|
|
|
|
|
|
**()测试示例**
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# 测试数据定义
|
|
|
|
|
[root@qfedu.com ~]# var=test
|
|
|
|
|
|
|
|
|
|
# 子shell中执行命令
|
|
|
|
|
[root@qfedu.com ~]# echo $var
|
|
|
|
|
test
|
|
|
|
|
[root@qfedu.com ~]# (var=notest;echo $var)
|
|
|
|
|
notest
|
|
|
|
|
[root@qfedu.com ~]# echo $var
|
|
|
|
|
test
|
|
|
|
|
# ()里的执行完毕后没有改变当前shell变量的值,说明在子shell中执行的
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**{}测试示例**
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
[root@qfedu.com ~]# {var=notest;echo $var}
|
|
|
|
|
{var=notest: command not found
|
|
|
|
|
test}
|
|
|
|
|
[root@qfedu.com ~]# {var=notest;echo $var;}
|
|
|
|
|
-su: syntax error near unexpected token `}'
|
|
|
|
|
[root@qfedu.com ~]# { var=notest;echo $var;}
|
|
|
|
|
notest
|
|
|
|
|
[root@qfedu.com ~]# echo $var
|
|
|
|
|
notest
|
|
|
|
|
# {}修改了变量的值。表明在当前shell中运行的
|
|
|
|
|
|
|
|
|
|
适用场景
|
|
|
|
|
# { ls;pwd;}>a.txt # 对比一下下面的输出有何不同
|
|
|
|
|
# ls;pwd>a.txt
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**[]测试示例-见test命令详解**
|
|
|
|
|
|
|
|
|
|
#### 2.双括号(()) [[]]
|
|
|
|
|
|
|
|
|
|
(()) 适合数值比较、运算 ,C语言形式
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
[root@wing tmp]# a=8
|
|
|
|
|
[root@wing tmp]# b=9
|
|
|
|
|
[root@wing tmp]# ((c=a+b))
|
|
|
|
|
[root@wing tmp]# echo $c
|
|
|
|
|
17
|
|
|
|
|
|
|
|
|
|
[root@wing tmp]# ((a>b))
|
|
|
|
|
[root@wing tmp]# echo $?
|
|
|
|
|
1
|
|
|
|
|
[root@wing tmp]# ((a<b))
|
|
|
|
|
[root@wing tmp]# echo $?
|
|
|
|
|
0
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
[[]] 适合条件测试,支持正则
|
|
|
|
|
|
|
|
|
|
#### 3.$修饰的括号
|
|
|
|
|
|
|
|
|
|
$(())、$[]、$()、${}
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
$(())、$[] 用途一致,用来作整数运算
|
|
|
|
|
$() 命令替换,等同反引号``,Shell会先执行括号内的cmd,然后将结果输出
|
|
|
|
|
${} Shell中变量的原形,用于限定变量名称的范围,并且支持通配符
|
|
|
|
|
|
|
|
|
|
# $(( ))还可以作不同进制(如二进制、八进位、十六进制)运算,只是输出结果皆为十进制而已。
|
|
|
|
|
|
|
|
|
|
# 16进位转十进制
|
|
|
|
|
[root@qfedu.com ~]# echo $((16#2a))
|
|
|
|
|
42
|
|
|
|
|
# 2进制转十进制
|
|
|
|
|
[root@server test]# echo $((2#11))
|
|
|
|
|
3
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 1、Shell 条件测试方法
|
|
|
|
|
|
|
|
|
|
| 方法 | 描述 |
|
|
|
|
|
| ---------------- | ------------------------------------------------------------ |
|
|
|
|
|
| test 测试表达式 | 利用test命令进行条件测试表达式,test命令与测试表达式之间至少有一个空格 |
|
|
|
|
|
| [ 测试表达式 ] | 通过[ ]中括号进行条件测试表达式,[]中括号边界与测试表达式之间至少有一个空格 |
|
|
|
|
|
| [[ 测试表达式 ]] | 通过[[ ]]双中括号进行条件测试表达式,[[ ]]双中括号与测试表达式之间至少有一个空格 |
|
|
|
|
|
| ((测试表达式)) | 通过(( ))双小括号进行条件测试表达式,( ))双小括号两端不需要空格,常用于整数对比 |
|
|
|
|
|
|
|
|
|
|
### 2、test测试
|
|
|
|
|
|
|
|
|
|
#### 1.文件操作符
|
|
|
|
|
|
|
|
|
|
**语法**
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# test 操作符 文件或目录
|
|
|
|
|
|
|
|
|
|
或者
|
|
|
|
|
|
|
|
|
|
# [ 操作符 文件或目录 ]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
| 操作符 | 描述 |
|
|
|
|
|
| ----------- | -------------------------------------------------- |
|
|
|
|
|
| **-d 文件** | 文件存在且为目录则为真 |
|
|
|
|
|
| **-f 文件** | 文件存在且为普通文件则为真 |
|
|
|
|
|
| **-e 文件** | 文件存在则为真,不辩别是目录还是文件 |
|
|
|
|
|
| **-s 文件** | 文件存在且文件大小不为0则为真 |
|
|
|
|
|
| **-r 文件** | 文件存在且可读则为真,与执行脚本的用户权限也有关 |
|
|
|
|
|
| **-w 文件** | 文件存在且可写则为真,与执行脚本的用户权限也有关 |
|
|
|
|
|
| **-x 文件** | 文件存在且可执行则为真,与执行脚本的用户权限也有关 |
|
|
|
|
|
| -L 文件 | 文件存在且为链接文件则为真 |
|
|
|
|
|
| f1 -nt f2 | 文件f1比文件f2新则为真,根据文件的修改时间计算 |
|
|
|
|
|
| f1 -ot f2 | 文件f1比文件f2旧则为真,根据文件的修改时间计算 |
|
|
|
|
|
|
|
|
|
|
**示例**
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
[root@qfedu.com ~]# test -d /home
|
|
|
|
|
[root@qfedu.com ~]# echo $?
|
|
|
|
|
0
|
|
|
|
|
[root@qfedu.com ~]# test -d /home11111
|
|
|
|
|
[root@qfedu.com ~]# echo $?
|
|
|
|
|
1
|
|
|
|
|
[root@qfedu.com ~]# [ -d /home ]
|
|
|
|
|
[root@qfedu.com ~]# [ ! -d /ccc ] && mkdir /ccc
|
|
|
|
|
[root@qfedu.com ~]# [ -d /ccc ] || mkdir /ccc
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### 2.字符串操作符
|
|
|
|
|
|
|
|
|
|
| 参数 | 示例 | 功能 |
|
|
|
|
|
| --------- | ------ | -------------------------------------------- |
|
|
|
|
|
| **-z** | s1 | 如果字符串s1的长度为0,则测试条件为真 |
|
|
|
|
|
| **-n** | s1 | 如果字符串s1的长度大于0,则测试条件为真 |
|
|
|
|
|
| | s1 | 如果字符串s1不是空字符串,则测试条件为真 |
|
|
|
|
|
| **=或==** | s1=s2 | 如果s1等于s2,则测试条件为真,“=”前后应有空格 |
|
|
|
|
|
| **!=** | s1!=s2 | 如果s1不等于s2,则测试条件为真 |
|
|
|
|
|
| < | s1<s2 | 如果按字典顺序s1在s2之前,则测试条件为真 |
|
|
|
|
|
| > | s1>s2 | 如果按自定顺序s1在s2之后,则测试条件为真 |
|
|
|
|
|
|
|
|
|
|
**示例**
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
# 字符串比较必须使用双引号
|
|
|
|
|
[root@qfedu.com ~]# [ "$USER" = "root" ];echo $?
|
|
|
|
|
0
|
|
|
|
|
[root@qfedu.com ~]# [ "$USER" == "root" ];echo $?
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
|
[root@qfedu.com ~]# BBB=""
|
|
|
|
|
[root@qfedu.com ~]# echo ${#BBB}
|
|
|
|
|
0
|
|
|
|
|
[root@qfedu.com ~]# [ -z "$BBB" ] # 字符长度是为0
|
|
|
|
|
[root@qfedu.com ~]# echo $?
|
|
|
|
|
0
|
|
|
|
|
[root@qfedu.com ~]# [ -n "$BBB" ] # 字符长度不为0
|
|
|
|
|
[root@qfedu.com ~]# echo $?
|
|
|
|
|
1
|
|
|
|
|
|
|
|
|
|
[root@qfedu.com ~]# var1=111
|
|
|
|
|
[root@qfedu.com ~]# var2=
|
|
|
|
|
[root@qfedu.com ~]# # var3变量没有定义
|
|
|
|
|
[root@qfedu.com ~]# echo ${#var1}
|
|
|
|
|
3
|
|
|
|
|
[root@qfedu.com ~]# echo ${#var2}
|
|
|
|
|
0
|
|
|
|
|
[root@qfedu.com ~]# echo ${#var3}
|
|
|
|
|
0
|
|
|
|
|
[root@qfedu.com ~]# [ -z "$var1" ];echo $?
|
|
|
|
|
1
|
|
|
|
|
[root@qfedu.com ~]# [ -z "$var2" ];echo $?
|
|
|
|
|
0
|
|
|
|
|
[root@qfedu.com ~]# [ -z "$var3" ];echo $?
|
|
|
|
|
0
|
|
|
|
|
[root@qfedu.com ~]# [ -n "$var1" ];echo $?
|
|
|
|
|
0
|
|
|
|
|
[root@qfedu.com ~]# [ -n "$var2" ];echo $?
|
|
|
|
|
1
|
|
|
|
|
[root@qfedu.com ~]# [ -n "$var3" ];echo $?
|
|
|
|
|
1
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### 3.整数操作符
|
|
|
|
|
|
|
|
|
|
| **在[]和test中使用** | **在[[ ]]和(( ))中使用** | **说明** |
|
|
|
|
|
| -------------------- | ------------------------ | -------------------------------- |
|
|
|
|
|
| -eq | ==或= | 等于,全拼为equal |
|
|
|
|
|
| -ne | != | 不等于,全拼为not equal |
|
|
|
|
|
| -gt | > | 大于,全拼为greater than |
|
|
|
|
|
| -ge | >= | 大于等于,全拼为greater or equal |
|
|
|
|
|
| -lt | < | 小于,全拼为less than |
|
|
|
|
|
| -le | <= | 小于等于,全拼为less or equal |
|
|
|
|
|
|
|
|
|
|
1、判断变量是不是数字
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
[root@qfedu.com ~]# num10=123
|
|
|
|
|
[root@qfedu.com ~]# num20=ssss1114ss
|
|
|
|
|
[root@qfedu.com ~]# [[ "$num10" =~ ^[0-9]+$ ]];echo $?
|
|
|
|
|
0
|
|
|
|
|
[root@qfedu.com ~]# [[ "$num20" =~ ^[0-9]+$ ]];echo $?
|
|
|
|
|
1
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2、数值比较 [ 整数1 操作符 整数2 ]
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
[root@qfedu.com ~]# disk_use=$(df -P |grep '/$' |awk '{print $5}' |awk -F% '{print $1}')
|
|
|
|
|
[root@qfedu.com ~]# [ $disk_use -gt 90 ] && echo "war......"
|
|
|
|
|
[root@qfedu.com ~]# [ $disk_use -gt 60 ] && echo "war......"
|
|
|
|
|
war......
|
|
|
|
|
|
|
|
|
|
[root@qfedu.com ~]# id -u
|
|
|
|
|
0
|
|
|
|
|
[root@qfedu.com ~]# [ $(id -u) -eq 0 ] && echo "当前是超级用户"
|
|
|
|
|
当前是超级用户
|
|
|
|
|
[alice@qfedu.com ~]$ [ $UID -eq 0 ] && echo "当前是超级用户" || echo "you不是超级用户"
|
|
|
|
|
you不是超级用户
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
3、C语言风格的数值比较
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
[root@qfedu.com ~]# ((1<2));echo $?
|
|
|
|
|
0
|
|
|
|
|
[root@qfedu.com ~]# ((1==2));echo $?
|
|
|
|
|
1
|
|
|
|
|
[root@qfedu.com ~]# ((1>2));echo $?
|
|
|
|
|
1
|
|
|
|
|
[root@qfedu.com ~]# ((1>=2));echo $?
|
|
|
|
|
1
|
|
|
|
|
[root@qfedu.com ~]# ((1<=2));echo $?
|
|
|
|
|
0
|
|
|
|
|
[root@qfedu.com ~]# ((1!=2));echo $?
|
|
|
|
|
0
|
|
|
|
|
[root@qfedu.com ~]# ((`id -u`>0));echo $?
|
|
|
|
|
1
|
|
|
|
|
[root@qfedu.com ~]# (($UID==0));echo $?
|
|
|
|
|
0
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### 4.逻辑操作符
|
|
|
|
|
|
|
|
|
|
| **在[]和test中使用** | **在[[ ]]和(( ))中使用** | **说明** |
|
|
|
|
|
| -------------------- | ------------------------ | ---------------------------------- |
|
|
|
|
|
| -a | && | and,与,两端都为真,则结果为真 |
|
|
|
|
|
| -o | \|\| | or,或,两端有一个为真,则结果为真 |
|
|
|
|
|
| ! | ! | not,非,两端相反,则结果为真 |
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
[root@qfedu.com ~]# [ 1 -lt 2 -a 5 -gt 10 ];echo $?
|
|
|
|
|
1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 0
|
|
|
|
|
[root@qfedu.com ~]# [ 1 -lt 2 -o 5 -gt 10 ];echo $?
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
|
[root@qfedu.com ~]# [[ 1 -lt 2 && 5 -gt 10 ]];echo $?
|
|
|
|
|
1
|
|
|
|
|
[root@qfedu.com ~]# [[ 1 -lt 2 || 5 -gt 10 ]];echo $?
|
|
|
|
|
0
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### 5、测试表达式区别总结
|
|
|
|
|
|
|
|
|
|
| **测试表达式符号** | **test** | **[ ]** | **[[ ]]** | **(( ))** |
|
|
|
|
|
| ------------------ | ---------------------------- | ---------------------------- | ------------------------------------------------- | ------------------- |
|
|
|
|
|
| 边界是否需要空格 | 需要 | 需要 | 需要 | 不需要 |
|
|
|
|
|
| 逻辑操作符 | !、-a、 -o | !、-a、 -o | !、&&、\|\| | !、&&、\|\| |
|
|
|
|
|
| 整数比较操作符 | -eq、-ne、-lt、-gt、-ge、-le | -eq、-ne、-lt、-gt、-ge、-le | -eq、-ne、-lt、-gt、-ge、-le或=、!=、<、>、>=、<= | =、!=、<、>、>=、<= |
|
|
|
|
|
| 字符串比较操作符 | =、==、!= | =、==、!= | =、==、!= | =、==、!= |
|
|
|
|
|
| 是否支持正则 | 不支持 | 不支持 | 支持 | 不支持 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
注:变量为空或未定义长度都为0
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
[root@qfedu.com ~]# [ "$USER" = "root" ];echo $?
|
|
|
|
|
0
|
|
|
|
|
[root@qfedu.com ~]# [ "$USER" = "alice" ];echo $?
|
|
|
|
|
1
|
|
|
|
|
[root@qfedu.com ~]# [ "$USER" != "alice" ];echo $?
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
|
[root@qfedu.com ~]# [ "$USER" = "root" ];echo $?
|
|
|
|
|
0
|
|
|
|
|
[root@qfedu.com ~]# [ "$USER" =~ ^r ];echo $?
|
|
|
|
|
bash: [: =~: binary operator expected
|
|
|
|
|
2
|
|
|
|
|
[root@qfedu.com ~]# [[ "$USER" =~ ^r ]];echo $? # 使用正则
|
|
|
|
|
0
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 3、Shell 分支if语句
|
|
|
|
|
|
|
|
|
|
#### 1、单分支 IF 条件语句
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
if [ 条件判断式 ];then
|
|
|
|
|
条件成立时,执行的程序
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# if语句使用fi结尾和一般语言使用大括号结尾不同
|
|
|
|
|
# [条件判断式] 就是使用test命令判断,所以中括号和条件判断式之间必须有空格
|
|
|
|
|
# then 后面跟符号条件之后执行的程序,可以放在[]之后,用";"分割。也可以换行写入,就不需要";"了
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### 2、双分支语句
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
if [ 条件判断式 ];then
|
|
|
|
|
条件成立时,执行的程序
|
|
|
|
|
else
|
|
|
|
|
条件不成立时,执行的另一个程序
|
|
|
|
|
fi
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### 3、多分支语句
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
if [ 条件判断式1 ]
|
|
|
|
|
then
|
|
|
|
|
当条件判断式1成立时,执行程序1
|
|
|
|
|
elif [ 条件判断式2 ]
|
|
|
|
|
then
|
|
|
|
|
当条件判断式2成立时,执行程序2
|
|
|
|
|
...省略更多条件....
|
|
|
|
|
else
|
|
|
|
|
当所有条件都不成立,最后执行此程序
|
|
|
|
|
fi
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 4、Shell 分支case语句
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
case $变量名 in
|
|
|
|
|
值1)
|
|
|
|
|
如果变量的值等于值1则执行指令1
|
|
|
|
|
;;
|
|
|
|
|
值2)
|
|
|
|
|
如果变量的值等于值2则执行指令2
|
|
|
|
|
;;
|
|
|
|
|
值3)
|
|
|
|
|
如果变量的值等于值3则执行指令3
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
如果变量的值不等于以上列出的任何值则执行默认指令
|
|
|
|
|
esac
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 二、Shell 编程之循环结构
|
|
|
|
|
|
|
|
|
|
### 1、Shell 循环 for 语句
|
|
|
|
|
|
|
|
|
|
for循环的运作方式,是将串行的元素一一取出,依序放入指定的变量中,然后重复执行含括的命令区域(在do和done 之间),直到所有元素取尽为止。
|
|
|
|
|
|
|
|
|
|
其中,串行是一些字符串的组合,彼此用$IFS所定义的分隔符(如空格符)隔开,这些字符串称为字段。
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
for 变量 in 值集合
|
|
|
|
|
do
|
|
|
|
|
执行命令
|
|
|
|
|
done
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
- for 每次从值集合中取一个值赋值给变量
|
|
|
|
|
|
|
|
|
|
- do - done 将赋值后的变量带入执行的命令得到执行结果 ,
|
|
|
|
|
|
|
|
|
|
- 重复以上两个步骤,直到值集合中的值被一一获取赋值给变量的到所有结果,循环结束
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
使用变量
|
|
|
|
|
num=8
|
|
|
|
|
for i in $(seq 2 $num)
|
|
|
|
|
do
|
|
|
|
|
echo $i
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
for i in {2..8}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
for((i=1;i<=10;i++))
|
|
|
|
|
do
|
|
|
|
|
echo $i
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
i=1 初始化i的值为1
|
|
|
|
|
i<=10 比较条件
|
|
|
|
|
i++ 步长 每次加1
|
|
|
|
|
|
|
|
|
|
嵌套的
|
|
|
|
|
for((i=1;i<=10;i++))
|
|
|
|
|
do
|
|
|
|
|
for((i=1;i<=10;i++))
|
|
|
|
|
do
|
|
|
|
|
echo $i
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
echo $i
|
|
|
|
|
done
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 2、Shell 循环 while 语句
|
|
|
|
|
|
|
|
|
|
1、while 循环语法
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
while 条件测试
|
|
|
|
|
do
|
|
|
|
|
执行命令
|
|
|
|
|
done
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
- while 首先进行条件测试,如果传回值为0(条件测试为真),则进入循环,执行命令区域,否则不进入循环
|
|
|
|
|
|
|
|
|
|
- 满足 while 测试条件,执行命令区域,直到 while 的测试条件不满足结束执行while循环(如果条件一直满足执行无穷循环)。
|
|
|
|
|
|
|
|
|
|
### 3、Shell 循环 until 语句
|
|
|
|
|
|
|
|
|
|
while循环的条件测试是测真值,until循环则是测假值。
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
until 条件测试
|
|
|
|
|
do
|
|
|
|
|
执行命令
|
|
|
|
|
done
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
- until 条件测试结果为假(传回值不为0),就进入循环。
|
|
|
|
|
|
|
|
|
|
- 条件测试不满足,执行命令区域。直到 until 条件满足,结束执行until 循环(如果条件一直不满足则执行无穷循环)。
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
#!/bin/bash
|
|
|
|
|
until ((i>10)) # 条件测试:只要i值未超过10,就进入循环
|
|
|
|
|
do
|
|
|
|
|
let sum+=i # sum+=i和sum=sum+i是一样的,sum累加上i
|
|
|
|
|
let ++i # i的值递增1,此行是改变条件测试的命令,一旦i大于10,可终止循环
|
|
|
|
|
done # 遇到done,回到 until条件测试
|
|
|
|
|
echo $sum # 直到 until 的条件满足显示sum的值
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
#!/bin/bash
|
|
|
|
|
a=1
|
|
|
|
|
b=1
|
|
|
|
|
until ((a>9)) # 条件测试:只要a值未超过9,就进入循环,一旦超过9就不执行,until和while条件相反,条件真就done结束
|
|
|
|
|
do
|
|
|
|
|
until ((b>a)) # b>a,一旦b大于a就不执行
|
|
|
|
|
do
|
|
|
|
|
let "c=a*b"
|
|
|
|
|
echo -n "$a*$b=$c "
|
|
|
|
|
let b++
|
|
|
|
|
done
|
|
|
|
|
let a++
|
|
|
|
|
let b=1
|
|
|
|
|
echo ""
|
|
|
|
|
done
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 4、Shell 循环控制
|
|
|
|
|
|
|
|
|
|
break,continue,exit 一般用于循环结构中控制循环的走向。
|
|
|
|
|
|
|
|
|
|
break和continue只能用在循环里面
|
|
|
|
|
|
|
|
|
|
exit可以用于脚本的任何地方
|
|
|
|
|
|
|
|
|
|
| **命令** | **说明** |
|
|
|
|
|
| ----------- | ------------------------------------------------------------ |
|
|
|
|
|
| break n | n 表示跳出循环的次数,如果省略 n 表示跳出整个循环 |
|
|
|
|
|
| continue n | n 表示退到第n层继续循环,如果省略n表示跳过本次循环进入下一次循环 |
|
|
|
|
|
| exit n | 退出当前的shell程序,并返回 n,n 也可以省略 |
|
|
|
|
|
| return | 用于返回一个退出值给调用的函数 |
|
|
|
|
|
| shift | 用于将参数列表list左移指定次数,最左端的那个参数就从列表中删除,其后边的参数继续进入循环 |
|
|
|
|
|
|
|
|
|
|
break[N]:提前结束第N层循环,最内层为第1层
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
while CONDITION1; do
|
|
|
|
|
CMD1
|
|
|
|
|
...
|
|
|
|
|
if CONDITION2; then
|
|
|
|
|
break
|
|
|
|
|
fi
|
|
|
|
|
CMDn
|
|
|
|
|
...
|
|
|
|
|
done
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
break:结束本次循环(整个),退出脚本
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
[root@qfedu.com ~]#vim test.sh
|
|
|
|
|
#!/bin/bash
|
|
|
|
|
for i in {1..10}
|
|
|
|
|
do
|
|
|
|
|
[ $i -eq 5 ] && break
|
|
|
|
|
echo i=$i
|
|
|
|
|
sleep 0.5
|
|
|
|
|
done
|
|
|
|
|
echo test is finished
|
|
|
|
|
|
|
|
|
|
[root@qfedu.com ~]#chmod +x test.sh
|
|
|
|
|
[root@qfedu.com ~]#./test.sh
|
|
|
|
|
i=1
|
|
|
|
|
i=2
|
|
|
|
|
i=3
|
|
|
|
|
i=4
|
|
|
|
|
test is finished
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[root@localhost ~]# cat break1.sh
|
|
|
|
|
#!/bin/bash
|
|
|
|
|
for((i=0;i<=5;i++))
|
|
|
|
|
do
|
|
|
|
|
if [ $i -eq 3 ];then
|
|
|
|
|
break;
|
|
|
|
|
fi
|
|
|
|
|
echo $i
|
|
|
|
|
done
|
|
|
|
|
echo "ok"
|
|
|
|
|
|
|
|
|
|
# 运行结果为:
|
|
|
|
|
[root@localhost ~]# bash break1.sh
|
|
|
|
|
0
|
|
|
|
|
1
|
|
|
|
|
2
|
|
|
|
|
ok
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为第1层
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
while CONDITION1;do
|
|
|
|
|
CMD1
|
|
|
|
|
...
|
|
|
|
|
if CONDITION2; then
|
|
|
|
|
continue
|
|
|
|
|
fi
|
|
|
|
|
CMDn
|
|
|
|
|
...
|
|
|
|
|
done
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
[root@localhost ~]# cat continue.sh
|
|
|
|
|
#!/bin/bash
|
|
|
|
|
for((i=0;i<=5;i++))
|
|
|
|
|
do
|
|
|
|
|
if [ $i -eq 3 ];then
|
|
|
|
|
continue;
|
|
|
|
|
fi
|
|
|
|
|
echo $i
|
|
|
|
|
done
|
|
|
|
|
echo "ok"
|
|
|
|
|
|
|
|
|
|
#运行结果为:
|
|
|
|
|
[root@localhost ~]# bash continue.sh
|
|
|
|
|
0
|
|
|
|
|
1
|
|
|
|
|
2
|
|
|
|
|
4
|
|
|
|
|
5
|
|
|
|
|
ok
|
|
|
|
|
|
|
|
|
|
[root@qfedu.com ~]#vim test.sh
|
|
|
|
|
#!/bin/bash
|
|
|
|
|
for i in {1..10}
|
|
|
|
|
do
|
|
|
|
|
[ $i -eq 5 ] && continue
|
|
|
|
|
echo i=$i
|
|
|
|
|
sleep 0.5
|
|
|
|
|
done
|
|
|
|
|
echo test is finished
|
|
|
|
|
|
|
|
|
|
[root@qfedu.com ~]#./test.sh
|
|
|
|
|
i=1
|
|
|
|
|
i=2
|
|
|
|
|
i=3
|
|
|
|
|
i=4
|
|
|
|
|
i=6
|
|
|
|
|
i=7
|
|
|
|
|
i=8
|
|
|
|
|
i=9
|
|
|
|
|
i=10
|
|
|
|
|
test is finished
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
exit 指令
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
[root@localhost ~]# cat exit.sh
|
|
|
|
|
#!/bin/bash
|
|
|
|
|
for((i=0;i<=5;i++))
|
|
|
|
|
do
|
|
|
|
|
if [ $i -eq 3 ];then
|
|
|
|
|
exit
|
|
|
|
|
fi
|
|
|
|
|
echo $i
|
|
|
|
|
done
|
|
|
|
|
echo "ok"
|
|
|
|
|
|
|
|
|
|
#运行结果为:
|
|
|
|
|
[root@localhost ~]# bash exit.sh
|
|
|
|
|
0
|
|
|
|
|
1
|
|
|
|
|
2
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 5、shift 指令(了解)
|
|
|
|
|
|
|
|
|
|
shift 命令用于将参数列表 list 左移指定次数,最左端的那个参数就从列表中删除,其后边的参数继续进入循环。
|
|
|
|
|
|
|
|
|
|
shift[N]:用于将参量列表 list 左移指定次数,缺省为左移一次。
|
|
|
|
|
|
|
|
|
|
参量列表 list 一旦被移动,最左端的那个参数就从列表中删 除。while 循环遍历位置参量列表时,常用到 shift
|
|
|
|
|
|
|
|
|
|
实例
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
[root@qfedu.com ~]# vim demo.sh
|
|
|
|
|
#!/bin/bash
|
|
|
|
|
while [ $# -gt 0 ]
|
|
|
|
|
do
|
|
|
|
|
echo $*
|
|
|
|
|
shift
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
[root@qfedu.com ~]# ./demo.sh a b c d e f g h
|
|
|
|
|
a b c d e f g h
|
|
|
|
|
b c d e f g h
|
|
|
|
|
c d e f g h
|
|
|
|
|
d e f g h
|
|
|
|
|
e f g h
|
|
|
|
|
f g h
|
|
|
|
|
g h
|
|
|
|
|
h
|
|
|
|
|
[root@qfedu.com ~]# vim shift.sh
|
|
|
|
|
#!/bin/bash
|
|
|
|
|
until [ -z "$1" ]
|
|
|
|
|
do
|
|
|
|
|
echo "$1"
|
|
|
|
|
shift
|
|
|
|
|
done
|
|
|
|
|
echo
|
|
|
|
|
|
|
|
|
|
[root@qfedu.com ~]# ./shift.sh a b c d e f g h
|
|
|
|
|
a
|
|
|
|
|
b
|
|
|
|
|
c
|
|
|
|
|
d
|
|
|
|
|
e
|
|
|
|
|
f
|
|
|
|
|
g
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 三、Shell 编程之函数
|
|
|
|
|
|
|
|
|
|
Shell 函数的本质是一段可以重复使用的脚本代码,这段代码被提前编写好了,放在了指定的位置,使用时直接调取即可
|
|
|
|
|
|
|
|
|
|
### 1、定义函数
|
|
|
|
|
|
|
|
|
|
可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。
|
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
# 方法一
|
|
|
|
|
function name() {
|
|
|
|
|
commands
|
|
|
|
|
[return value]
|
|
|
|
|
}
|
|
|
|
|
# 方法二
|
|
|
|
|
name() {
|
|
|
|
|
commands
|
|
|
|
|
[return value]
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
- function 是 Shell 中的关键字,专门用来定义函数;
|
|
|
|
|
- name 是函数名;
|
|
|
|
|
- commands 是函数要执行的代码,也就是一组语句;
|
|
|
|
|
- return value 表示函数的返回值,其中 return 是 Shell 关键字,专门用在函数中返回一个值;这一部分可以写也可以不写。
|
|
|
|
|
|
|
|
|
|
- 由 { } 包围的部分称为函数体,调用一个函数,实际上就是执行函数体中的代码。
|
|
|
|
|
- 函数的优势
|
|
|
|
|
- 方便n次使用,减少代码量,使之方便,整洁。
|
|
|
|
|
- 当需要修改里面的重复代码时,只需要修改一次函数即可实现需求;
|
|
|
|
|
- 将函数写进文件,需要时直接通过文件调用
|
|
|
|
|
|
|
|
|
|
### 2、调用函数
|
|
|
|
|
|
|
|
|
|
1、执行不带参数的函数
|
|
|
|
|
|
|
|
|
|
直接输入函数名即可,不需要带括号,
|
|
|
|
|
|
|
|
|
|
```undefined
|
|
|
|
|
functionName
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
- 执行函数时,函数名前的关键字function和函数名后面的()均不需要带
|
|
|
|
|
- 函数的定义必须要在执行的程序前定义或加载
|
|
|
|
|
|
|
|
|
|
2、执行带参数的函数
|
|
|
|
|
|
|
|
|
|
```undefined
|
|
|
|
|
functionName arg1 arg2
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
- Shell中的位置参数($1/$2.../$#/$?/$@)均可以做为函数的参数进行传递
|
|
|
|
|
- $0比较特殊,仍然是父脚本的名称
|
|
|
|
|
- 此时父脚本的参数会临时被函数的参数所掩盖或隐藏
|
|
|
|
|
- 函数的参数变量是在函数体内里面进行定义
|
|
|
|
|
|
|
|
|
|
调用函数示例
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
[root@qfedu.com ~]# cat testfunction.sh
|
|
|
|
|
#!/bin/bash
|
|
|
|
|
# first function
|
|
|
|
|
function HelloWorld() {
|
|
|
|
|
echo "Hello world"
|
|
|
|
|
}
|
|
|
|
|
# second function
|
|
|
|
|
Welcome() {
|
|
|
|
|
echo "Welcome to qfedu"
|
|
|
|
|
}
|
|
|
|
|
# third function
|
|
|
|
|
function HelloShell {
|
|
|
|
|
echo "Hello Shell"
|
|
|
|
|
}
|
|
|
|
|
# file functions
|
|
|
|
|
HelloWorld # 调用函数
|
|
|
|
|
Welcome
|
|
|
|
|
HelloShell
|
|
|
|
|
[root@qfedu.com ~]# bash testfunction.sh
|
|
|
|
|
Hello world
|
|
|
|
|
Welcome to qfedu
|
|
|
|
|
Hello Shell
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
从文件中调用函数示例
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
[root@qfedu.com ~]# cat filefunction.sh
|
|
|
|
|
function Sum () {
|
|
|
|
|
for((i=1;i<=100;i++))
|
|
|
|
|
do
|
|
|
|
|
((sum=sum+i))
|
|
|
|
|
done
|
|
|
|
|
echo '{1..100} sum is :' $sum
|
|
|
|
|
}
|
|
|
|
|
[root@qfedu.com ~]# cat filefunctionfromfile.sh
|
|
|
|
|
#!/bin/bash
|
|
|
|
|
path="/root/Test/filefunction.sh"
|
|
|
|
|
if [ -f ${path} ]
|
|
|
|
|
then
|
|
|
|
|
source $path # 加载函数
|
|
|
|
|
Sum # 调用函数
|
|
|
|
|
else
|
|
|
|
|
echo "file not exist or error"
|
|
|
|
|
fi
|
|
|
|
|
[root@qfedu.com ~]# bash filefunctionfromfile.sh
|
|
|
|
|
{1..100} sum is : 5050
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
函数参数传递示例
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
[root@qfedu.com ~]# cat functionwithargs.sh
|
|
|
|
|
#!/bin/bash
|
|
|
|
|
function Add () { # 定义函数
|
|
|
|
|
((sum=$1+$2))
|
|
|
|
|
echo "$1 + $2 sum is" ${sum}
|
|
|
|
|
}
|
|
|
|
|
Add $1 $2 # 调用函数并传递参数
|
|
|
|
|
|
|
|
|
|
[root@qfedu.com ~]# bash functionwithargs.sh 100 150
|
|
|
|
|
100 + 150 sum is 250
|
|
|
|
|
[root@qfedu.com ~]# bash functionwithargs.sh 509 150
|
|
|
|
|
509 + 150 sum is 659
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 3、return 返回函数结果
|
|
|
|
|
|
|
|
|
|
注意return的数字必须是数字,用引号包裹也一样
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
[root@qfedu.com ~]# cat functionwithreturn.sh
|
|
|
|
|
#!/bin/bash
|
|
|
|
|
function TestReturn() {
|
|
|
|
|
if [ -d $1 ];then
|
|
|
|
|
return "122"
|
|
|
|
|
else
|
|
|
|
|
return "222"
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TestReturn $1
|
|
|
|
|
result=$? # 获取函数返回值
|
|
|
|
|
if [ ${result} == "122" ]
|
|
|
|
|
then
|
|
|
|
|
echo "$1 exist ,return value is:" ${result}
|
|
|
|
|
else
|
|
|
|
|
echo "$1 not exist ,return value is:" ${result}
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
[root@qfedu.com ~]# bash functionwithreturn.sh /etc/sysconfiggg
|
|
|
|
|
/etc/sysconfiggg not exist ,return value is: 222
|
|
|
|
|
[root@qfedu.com ~]# bash functionwithreturn.sh /etc/sysconfig
|
|
|
|
|
/etc/sysconfig exist ,return value is: 122
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
在该示例中,主要通过 $? 获取返回值,但返回值的范围只能是 0~255
|
|
|
|
|
|
|
|
|
|
### 4、echo 返回函数结果
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
[root@qfedu.com ~]# cat functionwithecho.sh
|
|
|
|
|
#!/bin/bash
|
|
|
|
|
function TestReturn() {
|
|
|
|
|
if [ -d $1 ];then
|
|
|
|
|
echo "122"
|
|
|
|
|
else
|
|
|
|
|
echo "222"
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result=$(TestReturn $1) # 获取函数返回值
|
|
|
|
|
if [ ${result} == "122" ];then
|
|
|
|
|
echo "$1 exist ,return value is:" ${result}
|
|
|
|
|
else
|
|
|
|
|
echo "$1 not exist ,return value is:" ${result}
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
[root@qfedu.com ~]# bash functionwithecho.sh /etc/sysconfig
|
|
|
|
|
/etc/sysconfig exist ,return value is: 122
|
|
|
|
|
[root@qfedu.com ~]# bash functionwithecho.sh /etc/sysconfiggg
|
|
|
|
|
/etc/sysconfiggg not exist ,return value is: 222
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
该示例中,主要使用 $() 获取返回值,在该方法中,没有范围限制,是一种比较安全的返回方式。
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
[root@qfedu.com ~]# cat functionwithecho.sh
|
|
|
|
|
#!/bin/bash
|
|
|
|
|
function TestReturn() {
|
|
|
|
|
if [ -d $1 ]
|
|
|
|
|
then
|
|
|
|
|
echo "$1 exist"
|
|
|
|
|
else
|
|
|
|
|
echo "$1 not exist"
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result=$(TestReturn $1) # 获取返回值,返回的结果是字符串
|
|
|
|
|
if [ "${result}" == "$1 exist" ]
|
|
|
|
|
then
|
|
|
|
|
echo "$1 exist ,return value is:" ${result}
|
|
|
|
|
else
|
|
|
|
|
echo "$1 not exist ,return value is:" ${result}
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
[root@qfedu.com ~]# bash functionwithecho.sh /etc/sysconfiggg
|
|
|
|
|
/etc/sysconfiggg not exist ,return value is: /etc/sysconfiggg not exist
|
|
|
|
|
[root@qfedu.com ~]# bash functionwithecho.sh /etc/sysconfig
|
|
|
|
|
/etc/sysconfig exist ,return value is: /etc/sysconfig exist
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 5、全局变量和局部变量
|
|
|
|
|
|
|
|
|
|
全局变量在shell 脚本中任何地方都能使用;局部变量在函数内部使用,声明前加一个 local 就好
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
[root@qfedu.com ~]# cat test3.sh
|
|
|
|
|
function fun() {
|
|
|
|
|
a=$[ $b + 5 ]
|
|
|
|
|
c=$[ $a * 2 ]
|
|
|
|
|
}
|
|
|
|
|
a=4
|
|
|
|
|
b=6
|
|
|
|
|
fun
|
|
|
|
|
|
|
|
|
|
if [ $a -gt $b ]
|
|
|
|
|
then
|
|
|
|
|
echo "$a is larger than $b"
|
|
|
|
|
else
|
|
|
|
|
echo "$a is smaller than $b"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
function fun() {
|
|
|
|
|
local a=$[ $b + 5 ]
|
|
|
|
|
c=$[ $a * 2 ]
|
|
|
|
|
}
|
|
|
|
|
a=4
|
|
|
|
|
b=6
|
|
|
|
|
fun
|
|
|
|
|
|
|
|
|
|
if [ $a -gt $b ]
|
|
|
|
|
then
|
|
|
|
|
echo "$a is larger than $b"
|
|
|
|
|
else
|
|
|
|
|
echo "$a is smaller than $b"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
[root@qfedu.com ~]# bash test3.sh
|
|
|
|
|
11 is larger than 6
|
|
|
|
|
4 is smaller than 6
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 6、递归函数(纯了解)
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
[root@qfedu.com ~]# cat test6.sh
|
|
|
|
|
function factorial() {
|
|
|
|
|
if [ $1 -eq 1 ]
|
|
|
|
|
then
|
|
|
|
|
echo 1
|
|
|
|
|
else
|
|
|
|
|
local temp=$[ $1 - 1 ]
|
|
|
|
|
local result=$(factorial $temp)
|
|
|
|
|
echo $[ $result * $1 ]
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
read -p "Enter value: " value
|
|
|
|
|
result=$(factorial $value)
|
|
|
|
|
echo "The factorial of $value is: $result"
|
|
|
|
|
|
|
|
|
|
[root@qfedu.com ~]# bash test6.sh
|
|
|
|
|
Enter value: 5
|
|
|
|
|
The factorial of 5 is: 120
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**扩展**
|
|
|
|
|
|
|
|
|
|
**内建命令**
|
|
|
|
|
|
|
|
|
|
因为安装了shell而产生的命令
|