引言
Shell作为一种脚本编程语言,包含循环、分支等其他程序控制结构,从而能够轻松完成更加复杂的工作。本文主要讲了for、while语句的具体用法。
一、循环语句
1、for循环语句
使用 for 循环语句时,需要指定一个变量及可能的取值列表,针对每一个不同的取值重复执行相同的命令序列,直到变量值用完退出循环。
for 循环语句的语法结构如下:
for 变量名 in 取值列表
do
命令序列
done
for 语句的执行流程
- 首先将列表中的第1个取值赋给变量,并执行 do···done 循环体中的命令序列
- 然后将列表中的第2个取值赋给变量,并执行循环体中的命令序列……
- 以此类推,直到列表中的所有取值用完,最后将跳至 done 语句,表示结束循环
1.1 计算整数和
用户随机输入一个小于100的整数,并计算从1到该数之间所有整数的和
1.2 列出奇偶数
1.3 批量添加、删除用户
添加用户
调用这个文件,根据这个文件来创建用户名
创建用户成功
删除用户
1.4 根据IP地址列表检查主机状态
调用ip.txt
查看主机状态
1.5 密码验证
1.6 九九乘法表
2、while语句
for循环语句非常适用于列表对象无规律,且列表来源已固定(如某个列表文件)的场合。而对于要求控制循环次数、操作对象按数字顺序编号、按特定条件执行重复操作等情况,则更适合使用另一种循环—while语句。
- 使用 while循环语句时,可以根据特定的条件反复执行一个命令序列,直到该条件不再满足时为止。但是在脚本应用中,应该避免出现死循环的情况,否则后边的命令操作将无法执行。
- 循环体内的命令序列中应包括修改测试条件的语句,以便在适当的时候使测试条件不再成立,从而结束循环。
while循环语句的语法结构如下所示:
while 条件测试操作
do
命令序列
done
执行流程:
- 首先判断 while 后的条件测试操作结果,如果条件成立,则执行 do···done 循环体中的命令序列
- 返回 while 后再次判断条件测试结果,如果条件仍然成立,则继续执行循环体
- 再次返回到 while 后,判断条件测试结果…如此循环
- 直到 while 后的条件测试结果不再成立为止,最后跳转到 done 语句,表示结束循环
2.1 列出1-100之间能被3整除的数
vim zhengchu.sh
#!/bin/bash
i=1 //定义变量i=1
while [ $i -le 100 ] //重复测试$1是否小于等于100,直至$i等于100
do //命令列表
if [[ $i%3 -ge 0 ]] //条件检测 $i取余3,是否等于0
then //条件成立
echo "$i" //输出 $i的值
fi //结束判断
let i++ //每次循环i+1
done //结束循环
把-ge换成-ne就是不等于
2.2 猜数字
[root@zhang home]# vim text2.sh
#!/bin/bash
cnum=520
while true
do
read -p "请输入数字:" num
if [ $num -eq $cnum ]
then
echo "你猜对了"
break
elif [ $num -gt $cnum ]
then
echo "你猜大了"
elif [ $num -lt $cnum ]
then
echo "你猜小了"
fi
done
2.3 猜商品价格
[root@zhang while]# vim pricegame.sh
#!/bin/bash
PRICE=$(expr $RANDOM % 1000)
a=0
echo "商品实际价格范围为0-999,猜猜看是多少?"
while true
do
read -p "请输入你猜测的价格数目:" INT
let a++
if [ $INT -eq $PRICE ]
then
echo "恭喜你答对了,实际价格是 $PRICE"
echo "你总共猜测了 $a 次"
exit 0
elif [ $INT -gt $PRICE ]
then
echo "你猜高了!"
else
echo "你猜低了!"
fi
done
2.4 商场购物
#!/bin/bash
i=1
sum=0
while [ $i -le 3 ]
do
echo "进入第$i家商店"
read -p "是否进入看看(yes/no)" doing
while [ $doing = "yes" ]
do
echo "1:衣服 ¥200"
echo "2:鞋子 ¥999"
echo "3:帽子 ¥120"
echo "4:裤子 ¥279"
read -p "请选择你需要购买的商品的序列号:" num
case $num in
1)
echo "衣服购买成功"
expr $[sum+=200] &>/dev/null
;;
2)
echo "鞋子购买成功"
expr $[sum+=999] &>/dev/null
;;
3)
echo "帽子购买成功"
expr $[sum+=120] &>/dev/null
;;
*)
echo "裤子购买成功"
expr $[sum+=279] &>/dev/null
esac
read -p "是否进行购买(yes/no)?" doing
done
let i++
if [ $doing = "no" ]
then continue
fi
done
echo "购物总价为:$sum"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
3、until语句
重复测试某个条件,只要条件不成立则反复执行
语法结构如下所示:
until 条件测试操作
do
命令序列
done
3.1 计算1~50的和值
[root@zhang until]# vim 50.sh
#!/bin/bash
i=1 //定义变量i=1
sum=0
until [ $i -eq 51 ] //$i等于51时停止执行
do
sum+1=i //sum=sum+i
let i++ //每次循环i+1
done
echo "$sum //打印结果 $sum
二、Shell函数
- 将命令序列按格式写在一起
- 可方便重复使用命令序列
1、函数基本格式
[function] 函数名(){
命令序列
[return x] #使用return或exit可以显示的结束函数
}
或者
#也可以省略掉[function],它表示该函数的功能
函数名() { #函数名后面()是没有内容的
命令序列 #我们执行的命令内容放在{}里面
}
-
函数定义完之后并不会自动执行,需要调用才行
-
好处在于可以写一段功能代码作为函数,有需要就直接调用定义的时候哪怕出现语法错误也没关系,不调用就不会报错
-
当然我们写函数最终目的还是为了调用,为了实现某个功能块。
2、函数返回值
return表示退出函数并返回一个退出值,脚本中可以用$? 变量显示该值使用原则
- 函数一结束就取返回值,因为$?变量只返回执行的最后一条命令的退出状态码
- 退出状态码必须是0~255,超出时值将为256取余
返回值范围
[root@zhang hanshu]#vim retun.sh
#!/bin/bash
function test1 {
read -p "请输入数字:" num
return $[num*2]
}
test1
echo $?
[root@zhang hanshu]#sh retun.sh
请输入数字:3
6
[root@zhang hanshu]#sh retun.sh
请输入数字:127
254
[root@zhang hanshu]#sh retun.sh
请输入数字:128
0
3、函数的作用范围
- 函数在Shell脚本中仅在当前Shell环境中有效
- Shell脚本中变量默认全局有效
- 将变量限定在函数内部使用local命令
local一般用于局部变量声明,多在在函数内部使用。
- shell脚本中定义的变量是global的,其作用域从被定义的地方开始,到shell结束或被显示删除的地方为止。
- shell函数定义的变量默认是global的,其作用域从“函数被调用时执行变量定义的地方”开始,到shell结束或被显示删除处为止。函数定义的变量可以被显示定义成local的,其作用域局限于函数内。但请注意,函数的参数是local的。
- 如果同名,Shell函数定义的local变量会屏蔽脚本定义的global变量。
4、函数的参数
参数的用法
函数名称 参数1 参数2 参数3...
参数的表示方法
$1 $2 $3 ......${10} ${11}......
4.1 传参计算两个数的和
4.2 调用函数删除文件
4.3 用return返回值
5、递归函数
调用自己本身的函数
5.1 递归遍历目录
5.2 阶乘
**plan 1:**计算特定数的阶乘
**plan 2:**以递归方式计算随机数的阶乘
三、Shell数组
1、定义数组
可以在单行中使用数值列表来定义一个数组
array_var=(test1 test2 test3 test4)
#这些值将会存储在以0为起始索引的连续位置上
或者
#将数组定义为一组“索引—值”
array_var[0]="test1"
array_var[1]="test2"
array_var[2]="test3"
array_var[3]="test4"
精确的给每一个下标索引定义一个值加入数组,索引数字可以不连续
num=([0]=55 [1]=66 [2]=77 [4]=88)
数组名=([0]=value [1]=value [2]=value. . .)
先把要加入数组的元素全部先赋值给一个变量,然后引用这个变量加入到数组
list="11 12 13 14"
num=($list)
2、获取数组长度
${#arr}显示字符串长度
以列表形式打印出数组中的所有值
在数组中,@和*的效果一样
数组元素的遍历
3、元素切片
[root@zhang ~]# arrr=(10 20 30 40 50)
[root@zhang ~]# echo ${arr[*]}
10 20 30 40 50
[root@zhang ~]# echo ${arr[*]:2:3} #提取出第2个数后面的3个值
30 40 50
[root@zhang ~]# echo ${arr[*]:1:3} #提取出第1个数后面的3个值
20 30 40
[root@zhang ~]# echo ${arr[*]:0:4} #提取出第0个数后面的4个值
10 20 30 40
4、元素替换
[root@zhang ~]# arr=(1 3 5 7 9)
[root@zhang ~]# echo ${arr[*]}
1 3 5 7 9
[root@zhang ~]# echo ${arr[*]/3/88} #3指的是查找数组里面的字符,88指的是需要替换的字符
1 88 5 7 9
[root@zhang ~]# echo ${arr[*]/9/100}
1 3 5 7 100
5、元素删除
[root@zhang ~]# arr=(2 4 6 8 10)
[root@zhang ~]# echo ${arr[*]}
2 4 6 8 10
[root@zhang ~]# unset arr[2] #删除下标为2的值,即索引为2的值
[root@zhang ~]# echo ${arr[*]}
2 4 8 10
[root@zhang ~]# unset arr[4]
[root@zhang ~]# echo ${arr[*]}
2 4 8
6、冒泡排序
数组排序算法:冒泡排序
类似气泡上涌的动作,会将数据在数组中从小到大或者从大到小不断的向前移动。
基本思想:
冒泡排序的基本思想是对比相邻的两个元素值,如果满足条件就交换元素值,把较小的元素移动到数组前面,把大的元素移动到数组后面(也就是交换两个元素的位置),这样较小的元素就像气泡一样从底部上升到顶部。
算法思路:
冒泡算法由双层循环实现,其中外部循环用于控制排序轮数,一般为要排序的数组长度减1次,因为最后一次循环只剩下一个数组元素,不需要对比,同时数组已经完成排序了。而内部循环主要用于对比数组中每个相邻元素的大小,以确定是否交换位置,对比和交换次数随排序轮数而减少。
举例:
#!/bin/bash
array=(98 76 24 100 35 3)
echo "old_array:${array[*]}"
lt=${#array[*]}
#定义比较轮数,比较轮数为数组长度-1,从1开始
for ((i=1;i<$lt;i++))
do
#确定比较元素的位置,比较相邻两个元素,较大的数往后放,比较次数随比较轮数而
减少
for ((j=0;j<$lt-i;j++))
do
#定义第一个元素的值
first=${array[$j]}
#定义第二个元素的值
k=$[$j+1]
second=${array[$k]}
#如果第一个元素比第二个元素大,就互换
if [ $first -gt $second ];then
#把第一个元素的值保存到临时变量中
temp=$first
#把第二个元素值赋给第一个元素
array[$j]=$second
#把临时变量赋给第二个元素
array[$k]=$temp
fi
done
done
echo "new_array:${array[@]}"
四、总结
本文主要讲了三种循环语句和Shell函数的定义方法以及数组的使用方法。
for语句可根据已知的列表对象重复执行命令序列,更适合无规律的循环操作。
while语句可根据特定的条件重复执行命令序列,更适合有规律的循环操作。
until语句重复测试某个条件,只要条件不成立则反复执行。
Shell函数的调用
Shell数组的使用方法