971 lines
24 KiB
Markdown
971 lines
24 KiB
Markdown
|
||
# Shell流程控制-函数
|
||
|
||
## 一、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而产生的命令
|