一、for 循环语句
1.for 语句的结构
for 变量名 in 取值列表
do
命令序列
done
注意:for循环语句需要有一个取值列表
备注:
for 语句的执行流程:首先将列表中的第一个取值赋给变量,并执行do…done 循环体中的命令序列;然后将列表中的第二个取值赋给变量,并执行循环体中的命令序列……依此类推,直到列表中的所有取值用完,最后将跳至done 语句,表示结束循环
2.for 语句应用示例
(1)根据姓名列表批量添加/删除用户
[root@localhost ~]# vim /root/users.txt
//用做测试的列表文件
chenye
dengchao
zhangjie
[root@localhost ~]# vim uaddfor.sh
//批量添加用户的脚本
#!/bin/bash
ULIST=$(cat /root/users.txt)
for UNAME in $ULIST
do
useradd $UNAME
echo "123456" | passwd --stdin $UNAME &>/dev/null
done
[root@localhost ~]# chmod +x uaddfor.sh
[root@localhost ~]# ./uaddfor.sh
//测试并确认执行结果
[root@localhost ~]# tail -3 /etc/passwd
chenye:x:1005:1005::/home/chenye:/bin/bash
dengchao:x:1006:1006::/home/dengchao:/bin/bash
zhangjie:x:1007:1007::/home/zhangjie:/bin/bash
[root@localhost ~]# vim udelfor.sh
//批量删除用户的脚本
#!/bin/bash
ULIST=$(cat /root/users.txt)
for UNAME in $ULIST
do
userdel -r $UNAME &>/dev/null
done
[root@localhost ~]# chmod +x udelfor.sh
[root@localhost ~]# ./udelfor.sh
//测试并确认执行结果
[root@localhost ~]# id chenye
id: chenye: no such user
//提示无此用户
(2)根据 IP 地址列表检查主机状态
[root@localhost ~]# vim /root/ipadds.txt
//用做测试的列表文件
172.16.16.1
172.16.16.22
172.16.16.220
[root@localhost ~]# vim chkhosts.sh
//循环检查各主机的脚本
#!/bin/bash
HLIST=$(cat /root/ipadds.txt)
for IP in $HLIST
do
ping -c 3 -i 0.2 -W 3 $IP &> /dev/null
//-c 发送包的数量;-i 发送 ping 包间隔;-W 超时时间
if [ $? -eq 0 ]
then
echo "Host $IP is up."
else
echo "Host $IP is down."
fi
done
[root@localhost ~]# chmod +x chkhosts.sh
[root@localhost ~]# ./chkhosts.sh
//测试并确认执行结果
Host 172.16.16.1 is up.
Host 172.16.16.22 is up.
Host 172.16.16.220 is down.
二、使用 while 循环语句
1.while 语句的结构
while 条件测试操作
do
命令序列
done
备注:
while 语句的执行流程:首先判断while 后的条件测试操作结果,如果条件成立,则执行do…done 循环体中的命令序列;返回while 后再次判断条件测试结果,如果条件仍然成立,则继续执行循环体;再次返回到while 后,判断条件测试结果……如此循环,直到while 后的条件测试结果不再成立为止,最后跳转到done 语句,表示结束循环。
2.while 语句应用示例
(1)批量添加/删除规律编号的用户
[root@localhost ~]# vim uaddwhile.sh
//批量添加用户的脚本
#!/bin/bash
PREFIX="stu"
i=1
while [ $i -le 20 ]
do
useradd ${PREFIX}$i
echo "123456" | passwd --stdin ${PREFIX}$i &> /dev/null
let i++
done
[root@localhost ~]# chmod +x uaddwhile.sh
[root@localhost ~]# ./uaddwhile.sh
[root@localhost ~]# grep "stu" /etc/passwd | tail -3
stu18:x:1022:1022::/home/stu18:/bin/bash
stu19:x:1023:1023::/home/stu19:/bin/bash
stu20:x:1024:1024::/home/stu20:/bin/bash
[root@localhost ~]# vim udelwhile.sh
//批量删除用户的脚本
#!/bin/bash
PREFIX="stu"
i=1
while [ $i -le 20 ]
do
userdel -r ${PREFIX}$i第 8 页 共 21 页
let i++
done
[root@localhost ~]# chmod +x udelwhile.sh
[root@localhost ~]# ./udelwhile.sh
//测试并确认执行结果
[root@localhost ~]# id stu20
id: stu20:无此用户
//提示无此用户
(2)猜价格游戏
[root@localhost ~]# vim pricegame.sh
#!/bin/bash
PRICE=$(expr $RANDOM % 1000)
TIMES=0
echo "商品实际价格范围为 0-999,猜猜看是多少?"
while true
do
read -p "请输入你猜测的价格数目:" INT
let TIMES++
if [ $INT -eq $PRICE ] ; then
echo "恭喜你答对了,实际价格是 $PRICE"
echo "你总共猜测了 $TIMES 次"
exit 0
elif [ $INT -gt $PRICE ] ; then
echo "太高了!"
else
echo "太低了!"fi
done
[root@localhost ~]# chmod +x pricegame.sh
[root@localhost ~]# ./pricegame.sh
商品实际价格范围为 0-999,猜猜看是多少?
请输入你猜测的价格数目:500
太高了!
请输入你猜测的价格数目:250
太低了!
请输入你猜测的价格数目:375
太高了!
请输入你猜测的价格数目:280
太高了!
请输入你猜测的价格数目:265
太高了!
请输入你猜测的价格数目:253
恭喜你答对了,实际价格是 253
你总共猜测了 6 次
注意:linux中随机数的取值范围是0--32767,和什么数取余,取余后的最大数就是谁,不包含该数字
三、until 循环语句
1.until 语句的结构
until 条件测试操作
do
命令序列
done
备注:until 循环与 while 循环类似,while 循环能实现的脚本 until 同样也可以实现,但区别是 while 循环在条件为真是继续执行循环,而 until 则是在条件为假时执行循环。
2.until 语句应用示例
[root@localhost ~]# vim until_v1.sh
#!/bin/bash
i=0;s=0
until [ $i -eq 50 ]
do
let "i=$i+1";let "s=$s+$i"
done
echo 'sum(1..50)='$s
[root@localhost ~]# chmod +x sum1to50_until_v1.sh
[root@localhost ~]# ./sum1to50_until_v1.sh
sum(1..50)=1275
四、Shell 函数
1.函数的用法
[function] 函数名() {
命令序列
[return x]
}
- “function”关键字表示定义一个函数,可以省略;
- “{”符号表示函数执行命令的入口,该符号可以与函数名同行也可以在函数名下一行 的句首;
- “}”符号表示函数体结束,两个大括号之间{ }是函数体;
- “命令序列”部分可以是任意的 Shell 命令,也可以调用其他函数;
- “return”表示退出函数返回一个退出值,通过返回值判断执行是否成功,也可以使 用 exit 终止整个 Shell 脚本。
Shell 函数调用的方法为:函数名 [参数 1] [参数 2]。
2.案例 一个简单的函数脚本
[root@localhost ~]# cat exa1.sh
#!/bin/bash
zhangsan() {
echo "my name is zhangsan"
}
lisi() {
echo "my name is lisi"
}
zhangsan
lisi
[root@localhost ~]# sh exa1.sh
3.案例 带有参数的shell函数示例
[root@localhost ~]# cat exa2.sh
#!/bin/bash
name() {
echo "my name is $1"
}
name $1
[root@localhost ~]# sh exa2.sh zhangsan
my name is zhangsan
[root@localhost ~]# sh exa2.sh lisi
my name is lisi
4.案例 函数变量的作用范围
[root@localhost ~]# vim fun_scope.sh
myfun ()
{
local i
i=8
echo $i
}
i=9
myfun
echo $i
[root@localhost ~]# chmod +x fun_scope.sh
[root@localhost ~]# ./fun_scope.sh
备注:
通过内置命令local 将变量的值限定在函数内部。
5.案例 递归函数
Shell 也可以实现递归函数,就是可以调用自己本身的函数。
局部函数变量的一个特性是自成体系。除了从脚本命令行处获得的变量,自成体系的函数不需要使用任何外部资源。
这个特性使得函数可以递归地调用,也就是说,函数可以调用自己来得到结果。通常递归函数都有一个最终可以迭代到的基准值。许多高级数学算法用递归对复杂的方程进行逐级规约,直到基准值定义的那级。
[root@localhost ~]# vim fun_recursion.sh
#!/bin/bash
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@localhost ~]# ./fun_recursion.sh
五、Shell 数组
Shell 中的数组与Java、C、Python 不同,只有一维数组,没有二维数组。
1.定义数组的方法
数组常用定义方法包括以下几种。
方法一:
数组名=(value0 value1 value2 ...)
方法二:
数组名=([0]=value [1]=value [2]=value ...)
方法三:
列表名=”value0 value1 value2 ...”
数组名=($列表名)
方法四:
数组名[0]=”value”
数组名[1]=”value”
数组名[2]=”value”
2.获取数组长度
[root@localhost ~]# arr_number=(1 2 3 4 5)
[root@localhost ~]# arr_length=${#arr_number[*]}
[root@localhost ~]# echo $arr_length
5
[root@localhost ~]# arr_length_1=${#arr_number[@]}
[root@localhost ~]# echo $arr_length_1
5
备注:
当 $* 和 $@ 不被双引号" "包围时,它们之间没有任何区别,都是将接收到的每个参数看做一份数据,彼此之间以空格来分隔。
但是当它们被双引号" "包含时,就会有区别了:
- "∗"会将所有的参数从整体上看做一份数据,而不是把每个参数都看做一份数据。
- "@"仍然将每个参数都看作一份数据,彼此之间是独立的。
[root@localhost ~]# vim aa
#!/bin/bash
echo "-- \$* 演示 ---"
for i in "$*"; do
echo $i
done
echo "-- \$@ 演示 ---"
for i in "$@"; do
echo $i
done
[root@localhost ~]# bash aa 1 2 3
3.读取某下标赋值
[root@localhost ~]# arr_index2=${arr_number[2]}
或
[root@localhost ~]# echo ${arr_number[2]}
//第三个元素
[root@localhost ~]# echo $arr_index2
3
或
echo ${aaa[3]}
4.数组遍历
[root@localhost ~]# vim array_traverse.sh
#!/bin/bash
arr_number=(1 2 3 4 5)
for v in ${arr_number[@]}
do
echo $v
done
[root@localhost ~]# chmod +x array_traverse.sh
[root@localhost ~]# ./array_traverse.sh
1
2
3
4
5
5.数组切片
[root@centos-7 ~]# arr=(1 2 3 4 5)
[root@centos-7 ~]# echo ${arr[@]}
//输出整个数组
1 2 3 4 5
[root@centos-7 ~]# echo ${arr[@]:0:2}
//${数组名[@或*]:起始位置:长度}
1 2
[root@centos-7 ~]# echo ${arr[@]:2:3}
3 4 5
备注:
切片就是输出数组中指定连续的若干位,从第几位开始的往后几个数
6.数组替换
[root@centos-7 ~]# arr=(1 2 3 4 5)
[root@centos-7 ~]# echo ${arr[@]/4/66}
//${数组名[@或*]/查找字符/替换字符}
1 2 3 66 5
[root@centos-7 ~]# echo ${arr[@]}
//并不会替换数组原有内容
1 2 3 4 5
[root@centos-7 ~]# arr=(${arr[@]/4/66})
//要实现改变原有数组,可通过重新赋值实现
[root@centos-7 ~]# echo ${arr[@]}
1 2 3 66 5
7.数组删除
[root@centos-7 ~]# arr=(1 2 3 4 5)
[root@centos-7 ~]# unset arr
//删除数组
[root@centos-7 ~]# echo ${arr[*]}
[root@centos-7 ~]# arr=(1 2 3 4 5)
[root@centos-7 ~]# unset arr[2]
//删除第三个元素
[root@centos-7 ~]# echo ${arr[*]}
1 2 4 5
六、Shell 脚本调试
除了 echo 命令之外,bash Shell 也有相应参数可以调试脚本。使用 bash 命令参数调 试,命令的语法为:
sh [-nvx] 脚本名
- -n:不会执行该脚本,仅查询脚本语法是否有问题,如果没有语法问题就不显示任 何内容,如果有问题会提示报错。
- -v:在执行脚本时,先将脚本的内容输出到屏幕上然后执行脚本,如果有错误,也 会给出错误提示。
- -x:将执行的脚本内容输出到屏幕上,这个是对调试很有用的参数。
当脚本文件较长时,可以使用 set 命令指定调试一段脚本。
#!/bin/bash
set -x
//开启调试模式
read -p "请输入您的分数(0-100):" GRADE
if [ $GRADE -ge 85 ] && [ $GRADE -le 100 ]
then
echo "$GRADE 分!优秀"
set +x
//关闭调试模式
elif [ $GRADE -ge 70 ] && [ $GRADE -le 84 ]
then
echo "$GRADE 分,合格"
else
echo "$GRADE 分?不合格"
fi