目录
一、for循环
含义:以次数循环……依次将列表中的元素(变量和命令)赋值给变量名:每次赋值后会执行一个循环体,知道列表中的元素耗尽循环结束。
语法结构
(1)列表循环
(2)不带列表循环
(3)类C风格的for循环
附1小技巧:花括号{}和seq在for循环的应用:
for i in {1..50..2} 1-50的奇数
for i in {2..50..2} 1-50的偶数
for i in {10..1} 1-10倒序排列
for i in $(seq 10) 1-10正序排列
for i in $(seq 10 -1 1) 1-10倒序排列
for i in $(seq 1 2 10) 1-10的奇数,中间为步长
for i in $(seq 0 2 10) 1-10的偶数,中间为步长
for ((expr1;expr2;expr3))
do
command
done
expr1:定义变量并赋初值
expr2:决定是否循环
expr3:决定循环变量如何改变,决定循环什么时候退出
二、while语句
while循环一般用于有条件判断的循环,若判断条件为真,则进入循环,当条件为假就跳出循环。
语法结构
while 表达式
do
command
done
例1:打印1-5
[root@wangming opt]# cat wh1.txt
#!/bin/bash
i=1
while [ $i -le 5 ]
do
echo $i
let i++ //注意这里如果不改变$i的值,会变成死循环
done
echo "最后的值为:$i"
[root@wangming opt]# sh wh1.txt
1
2
3
4
5
最后的值为:6
[root@wangming opt]#
例2:输出1-20之间不能被3整除的数字
[root@wangming opt]# cat wh2.txt
#!/bin/bash
i=1
while [ $i -le 20 ]
do
if [[ $i%3 -ne 0 ]];then
echo "$i"
fi
let i++
done
[root@wangming opt]# sh wh2.txt
1
2
4
5
7
8
10
11
13
14
16
17
19
20
[root@wangming opt]#
while死循环
while [ 1 -eq 1 ] //写一个永远为真的表达式,1等于1这个条件永远为真,所以这个脚本会一直循环下去。
例3:猜数字,猜不对就一直猜
[root@wangming opt]# cat wh3.txt
#!/bin/bash
num=0
a=1
sorce=$[$RANDOM % 100]
while [ $a -lt 2 ]
do
read -p "请输入你猜的数字:" price
if [ $price -eq $sorce ];then
echo "你猜对了"
let num++
let a++
elif [ $price -gt $sorce ];then
echo "你猜大了"
let num++
elif [ $price -lt $sorce ];then
echo "你猜小了"
let num++
fi
done
echo "你一共猜了$num次!"
[root@wangming opt]# sh wh3.txt
请输入你猜的数字:50
你猜大了
请输入你猜的数字:25
你猜小了
请输入你猜的数字:35
你猜大了
请输入你猜的数字:30
你猜小了
请输入你猜的数字:33
你猜对了
你一共猜了5次!
[root@wangming opt]#
例4:
[root@wangming opt]# cat wh4.txt
#!/bin/bash
i=1
sum=0
while [ $i -le 5 ]
do
echo "进入第$i家商店"
read -p "是否进入看看(yes/no)" doing
while [ $doing = "yes" ]
do
echo "1:衣服¥200"
echo "2:鞋子¥150"
echo "3:手套¥40"
echo "4:裤子¥155"
read -p "请选择需要购买的商品序列:" num
case $num in
1)
echo "衣服购买成功"
expr $[sum+=200] &> /dev/null
;;
2)
echo "鞋子购买成功"
expr $[sum+=150] &> /dev/null
;;
3)
echo "手套购买成功"
expr $[sum+=40] &> /dev/null
;;
*)
expr "裤子购买成功"
$[sum+=155] &> /dev/null
esac
read -p "是否继续进行购买(yes/no)" doing
done
let i++
if [ $doing = "no" ];then
continue
fi
done
echo "购物总价:$sum"
[root@wangming opt]# sh wh4.txt
进入第1家商店
是否进入看看(yes/no)yes
1:衣服¥200
2:鞋子¥150
3:手套¥40
4:裤子¥155
请选择需要购买的商品序列:1
衣服购买成功
是否继续进行购买(yes/no)yes
1:衣服¥200
2:鞋子¥150
3:手套¥40
4:裤子¥155
请选择需要购买的商品序列:4
裤子购买成功
是否继续进行购买(yes/no)yes
1:衣服¥200
2:鞋子¥150
3:手套¥40
4:裤子¥155
请选择需要购买的商品序列:2
鞋子购买成功
是否继续进行购买(yes/no)no
进入第2家商店
是否进入看看(yes/no)yes
1:衣服¥200
2:鞋子¥150
3:手套¥40
4:裤子¥155
请选择需要购买的商品序列:3
手套购买成功
是否继续进行购买(yes/no)no
进入第3家商店
是否进入看看(yes/no)no
进入第4家商店
是否进入看看(yes/no)no
进入第5家商店
是否进入看看(yes/no)no
购物总价:545
[root@wangming opt]#
三、until循环
跟while相反,条件为假进入循环,条件为真退出循环
语法结构
until 表达式
do
command
done
例1: 计算1-50的和1275
[root@wangming opt]# cat un1.txt
#!/bin/bash
i=1
sum=0
until [ $i -eq 51 ]
do
sum=$[$i+$sum]
let i++
done
echo "$sum"
[root@wangming opt]# sh un1.txt
1275
四、 循环控制语句
for循环一般会搭配条件判断语句和流程控制语句一起执行,那么就会出现需要跳过循环和中止循环的情况,控制循环的命令有以下3个。
4.1、continue
继续,但不会执行循环体内下面的代码了,开始重新开始下一次循环
#!/bin/bash
for ((i=1;i<=5;i++))
do
if [ $i -eq 3 ];then
continue
else
echo $i
fi
done
4.2、break
打断,马上停止本次循环,执行循环体外的代码
#!/bin/bash
for ((i=1;i<=10;i++))
do
if [ $i -eq 8 ];then
break
else
echo $i
fi
done
4.3、exit
直接跳出程序,后面可跟状态返回码如exit 1等等
#!/bin/bash
for i in {1..5}
do
if [ $i -eq 3 ];then
exit 100
else
echo $i
fi
done
echo hi
五、shell函数
5.1、函数的定义
1、
function 函数名 {
command
} //这是一种规范写法2、
函数名(){ //最常用因为最简洁
command
}
5.2、函数的调用
注意①:函数名必须是唯一,如果先定义了一个,再用同样的名称定义,第二个会覆盖第一个的功能,出现了你不想要的结果,所以这里一定要注意不要重名!
注意②:调用函数之前必须先进行定义!
注意③:不一定要在脚本开头就定义函数,只要调用之前定义就可以
5.3、函数的传参
例1:两个数求和
#!/bin/bash
sum(){
read -p "请输入第一个数:" NUM1
read -p "请输入第二个数:" NUM2
echo "你输入的两个数为: $NUM1 和$NUM2 "
SUM=$(( NUM1+$NUM2))
echo “两个数的和为: $SUM”
}
sum
例2:阶乘
#!/bin/bash
jiecheng (){
cheng=1
read -p "请问您想算几的阶乘:" num //①给用户提示输入
for i in `seq $num`
do
let cheng=$i*$cheng
done
echo $cheng
}
jiecheng
5.4、函数的作用范围
在 Shell 脚本中函数的执行并不会开启一个新的子 Shell,而是仅在当前定义的 Shell 环境中有效。如果Shell脚本中的变量没有经过特殊设定,默认在整个脚本中都是有效的。在编写脚本时,有时需要将变量的值限定在函数内部,可以通过内置命令local来实现。函数内部变量的使用,可以避免函数内外同时出现同名变量对脚本结果的影响。
shell脚本中变量默认全局有效
local命令:将变量限定在函数内部使用
函数的返回值,用return来自定义返回码
函数的返回值就是函数当中运行最后一条命令的状态码,默认成功为0,失败为非0值,可以通过$?查看
但是可以自己自定义返回码,用return
1、return的值范围是0-255
2、遇到return即结束函数不会再往下执行
本地变量与全局变量:
在脚本里定义的变量或者在函数体没有声明为本地变量的都为全局变量,意思是在当前shell环境都识别;
如果需要这个变量只在函数中使用则可以在函数中用local关键字声明,这样即使函数体外有个重名的变量也没关系,不影响在函数体的使用。
5.5、函数的递归
函数自己调用自己的本身
例1:列出目录内文件列表,目录用蓝色表示,文件显示层级关系
#!/bin/bash
list(){
for i in $1/*
do
if [ -d $i ];then
echo -e "\e[34m$i\e[0m"
list $i " $2"
else
echo "$2$i"
fi
done
}
list $1 $2
例2:计算5的阶乘
#阶乘 5! 5*4*3*2*1
#!/bin/bash
fa () {
if [ $1 -eq 1 ]
then
echo 1
else
local tp=$[$1 - 1]
local res=$(fa $tp)
echo $[ $1 * $res ]
# 5 * $res(4*$res(3*$res(2*$res(1))))
fi
}
read -p "请输入:" num
res=$(fa $num)
echo $res
六、数组
6.1、 数组的定义
数组是存放相同类型数据的集合,在内存中开辟了连续的空间,通常配合循环使用
6.2、数组的分类
普通数组:不需要声明直接定义,下标索引只能是整数
关联数组:需要用declare -A声明否则系统不识别,索引可以是字符串
6.3、数组的定义方式
第一种:直接把要加入数组的元素用小括号括起来,中间用空格分开
num=(11 22 33 44)
${#num} 显示字符串长度
数组名= (value0 value1 value2)
第二种:精确的给每一个下标索引定义一个值加入数组,索引数字可以不连续
num=([0]=55 [1]=66 [2]=77 [4]=88)数组名=([0]=value [1] =value [2] =value...)
第三种:先把要加入数组的元素全部先赋值给一个变量,然后引用这个变量加入到数组
list=“11 12 13 14”
num=($list)
第四种 根据下标定义
数组名[0]=“11”
数组名[0]=“22”
数组名[0]=“33”数组名[0]="value"
数组名[1]="value"
数组名[2]="value"
6.4、数组的数据类型
数值类型
字符类型:使用“ ” 或 ‘ ’ 定义
6.4.1、数组简单格式
6.4.2、 元素遍历
#!/bin/bash
arr=(1 2 3 4 5 6)
for i in ${arr[*]} 或for i in ${arr[@]}
do
echo $i
done
6.4.3、 元素切片
arr=(1 2 3 4 5 6)
echo ${arr[*]} #输出整个数组
echo ${arr[*]:2:3} #提取从索引2开始的3个元素
echo ${arr[*]:0:2}
6.4.4、元素替换和元素删除
arr=(1 2 3 4 5 6)
echo ${arr[*]/3/55} //${数组名[@或*]/查找字符/替换字符}
echo ${arr[*]} //并不会替换数组原有内容
arr=(${arr[*]/3/55}) //要实现改变原有数组,可通过重新赋值实现 arr=${arr[*]/3/55}
arr=(${arr[*]/3/55})
echo ${arr[@]}
arr=(1 2 3 4 5 6)
unset arr //删除数组
echo $ { arr[* ]}
arr=(1 2 3 4 5 6)
unset arr[4] //删除第四个元素
echo $ {arr[*]}
6.4.5、冒泡排序
冒泡排序的基本思想是对比相邻的两个元素值,如果满足条件就交换元素值,把较小的元素移动到数组前面,把大的元素移动到数组后面(也就是交换两个元素的位置)。
算法思路
冒泡算法由双层循环实现,其中外部循环用于控制排序轮数,一般为要排序的数组长度减1次,因为最后一次循环只剩下一个数组元素,不需要对比,同时数组已经完成排序了。而内部循环主要用于对比数组中每个相邻元素的大小,以确定是否交换位置,对比和交换次数随排序轮数而减少。