文章目录
一 循环语句
1.1 for循环语句的结构
- 读取不同的变量值,用来逐个执行同一组命令
示例1
- 批量添加用户
用户名存放在users。txt文件中,每行一个
初始密码均为123456
验证脚本
[root@localhost ~]# vi /root/users.txt
chen
wen
jian
[root@localhost ~]# vi 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
chen:x:1001:1001::/home/chen:/bin/bash
wen:x:1002:1002::/home/wen:/bin/bash
jian:x:1003:1003::/home/jian:/bin/bash
示例2
- 根据ip地址检查主机状态
IP地址存放在ipadds.txt文件中,每行一个
使用ping命令检测个主机的连通性
[root@localhost ~]# vi /root/ipadds.txt
20.0.0.1
20.0.0.2
20.0.0.10
20.0.0.21
20.0.0.100
[root@localhost ~]# vi 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
if [ $? -eq 0 ]
then
echo "Host $IP is up" && echo "Host $IP is up" >>/root/ipup.txt
else
echo "Host $IP is down" && echo "Host $IP is down" >>/root/ipdown.txt
fi
done
[root@localhost ~]# chmod +x chkhosts.sh
[root@localhost ~]# ./chkhosts.sh
Host 20.0.0.1 is up
Host 20.0.0.2 is up
Host 20.0.0.10 is down
Host 20.0.0.21 is up
Host 20.0.0.100 is down
[root@localhost ~]# ll
......
-rw-r--r-- 1 root root 49 Aug 13 09:17 ipadds.txt
-rw-r--r-- 1 root root 196 Aug 13 09:19 ipdown.txt
-rw-r--r-- 1 root root 224 Aug 13 09:19 ipup.txt
......
[root@localhost ~]# cat ipup.txt
Host 20.0.0.1 is up
Host 20.0.0.2 is up
Host 20.0.0.21 is up
[root@localhost ~]# cat ipdown.txt
Host 20.0.0.10 is down
Host 20.0.0.100 is down
1.2 while语句的结构
- 重复测试某个条件,只要条件成立则反复执行
示例1
- 批量添加用户
用户名以stu开头,按数字顺序进行编号
一共添加20个用户,即stu1、stu2…stu20
初始密码均为123456
[root@localhost ~]# vi usaddwhile.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 usaddwhile.sh
[root@localhost ~]# ./usaddwhile.sh
[root@localhost ~]# grep "stu" /etc/passwd
stu1:x:1001:1001::/home/stu1:/bin/bash
stu2:x:1002:1002::/home/stu2:/bin/bash
stu3:x:1003:1003::/home/stu3:/bin/bash
stu4:x:1004:1004::/home/stu4:/bin/bash
stu5:x:1005:1005::/home/stu5:/bin/bash
stu6:x:1006:1006::/home/stu6:/bin/bash
stu7:x:1007:1007::/home/stu7:/bin/bash
stu8:x:1008:1008::/home/stu8:/bin/bash
stu9:x:1009:1009::/home/stu9:/bin/bash
stu10:x:1010:1010::/home/stu10:/bin/bash
stu11:x:1011:1011::/home/stu11:/bin/bash
stu12:x:1012:1012::/home/stu12:/bin/bash
stu13:x:1013:1013::/home/stu13:/bin/bash
stu14:x:1014:1014::/home/stu14:/bin/bash
stu15:x:1015:1015::/home/stu15:/bin/bash
stu16:x:1016:1016::/home/stu16:/bin/bash
stu17:x:1017:1017::/home/stu17:/bin/bash
stu18:x:1018:1018::/home/stu18:/bin/bash
stu19:x:1019:1019::/home/stu19:/bin/bash
stu20:x:1020:1020::/home/stu20:/bin/bash
示例2
- 猜商品价格游戏
通过变量RANDOM获得随机数
提示用户猜测并记录次数,猜中后退出循环
[root@localhost ~]# vi 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
1.3 until循环语句
- 重复测试某个条件,只要条件不曾李则反复执行
实例1
- 计算1~50的和值
通过循环累加的方式计算1~50的和值
[root@localhost ~]# vi sum1to50.sh
#!/bin/bash
i=0
s=0
until [ $i -ge 50 ]
do
let "i=$i+1"
let "s=$s+$i"
done
echo "1加到50的和为:" $s
[root@localhost ~]# chmod +x sum1to50.sh
[root@localhost ~]# ./sum1to50.sh
1加到50的和为: 1275
shell函数
2.1 shell函数
- 将命令序列按格式写在一起
- 可方便重复使用命令序列
- Shell函数定义
#使用return或exit可以显示的结束函数
[ function 函数名(){
命令序列
[return x]
}
- 调用函数的方法
函数名 [参数1] [参数2]
实例
- 两个数字求和
通过sum() {}定义函数
使用read命令交互输入两个数并求和
[root@localhost ~]# vi sum.sh
#!/bin/bash
sum(){
read -p "请输入第一个数:" NUM1
read -p "请输入第二个数:" NUM2
echo "你输入的两个数为:" $NUM1和$NUM2
SUM=$((NUM1 + NUM2))
echo "两个数的和为: $SUM"
}
sum
[root@localhost ~]# ./sum.sh
请输入第一个数:10
请输入第二个数:20
你输入的两个数为: 10和20
两个数的和为: 30
2.2 函数的作用范围
-
函数在Shell脚步中仅在当前Shell环境中有效
-
Shell脚本中变量默认全局有效
-
讲变量限定在函数内部使用local命令
-
示例
1. 函数内部变量通过local来实现 2. 通过定义myfun函数,在其内部设置举报变量 3. 函数内部和外部分别赋值,进行结束验证
[root@localhost ~]# vi 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
8
9
2.3 函数的参数
- 参数的用法
函数名称 参数1 参数2 参数3 ......
- 参数的表示方法
$1 $2 $3 … ${10} ${11}…
实例
- 通过函数参数将日志信息写入文件
通过定义appendfile函数实现
[root@localhost ~]# vi write_log.sh
#!/bin/bash
mydir="/data"
outfile="${mydir}/my.log"
[ -e "${mydir}" ] || mkdir -p ${mydir}
appendfile()
{
echo "$2" >> "$1"
}
appendfile ${outfile} "first line content"
appendfile ${outfile} "second line content"
[root@localhost ~]# chmod +x write_log.sh
[root@localhost ~]# ./write_log.sh
[root@localhost ~]# cat /data/my.log
first line content
second line content
2.4 递归函数
- 调用自己本身的函数
实例
- 递归遍历目录
通过定义递归函数list_files来实现
[root@localhost ~]# vi fun_recursion.sh
function list_files()
{
for f in `ls $1`;
do
if [ -d "$1/$f" ];
then
echo "$2$f"
list_files "$1/$f" " $2"
else
echo "$2$f"
fi
done
}
list_files "/var/log" ""
[root@localhost ~]# chmod +x fun_
fun_recursion.sh fun_scope.sh
[root@localhost ~]# chmod +x fun_recursion.sh
[root@localhost ~]# ./fun_recursion.sh
anaconda
anaconda.log
ifcfg.log
journal.log
ks-script-9EcVF8.log
packaging.log
program.log
storage.log
......
三 Shell数组
3.1 Shell数组
-
应用场景包括
获取数组长度
获取元素长度
遍历元素
元素切片
元素替换
元素删除
… -
数组定义方法
#方法一
数组名=(value0 value1 value2 ...)
#方法二
数组名=([0]=value [1]=value [2]=value ...)
#方法三
列表名="value0 value1 value2 ..."
数组名=($列表名)
- 数组包括的数据类型
·数值类型
·字符类型
----使用 “ ” 或 ‘ ’ 定义
数组名[0]=“value”
数组名[1]=“value”
数组名[2]=“value”
- 获取数组长度
[root@localhost ~]# a=(1 2 3 4 5)
[root@localhost ~]# a=${#a[*]}
[root@localhost ~]# echo $a
5
- 读取某下标赋值
[root@localhost ~]# a2=${a[2]} //第三个元素
[root@localhost ~]# echo $a2
3
- 数组遍历
[root@localhost ~]# vi a.sh
#!/bin/bash
a=(1 2 3 4 5)
for v in ${a[*]}
do
echo $v
done
[root@localhost ~]# chmod +x a
anaconda-ks.cfg a.sh
[root@localhost ~]# chmod +x a.sh
[root@localhost ~]# ./a.sh
1
2
3
4
5
- 数组切片
[root@localhost ~]# a=(1 2 3 4 5)
[root@localhost ~]# echo ${a[*]} //输出整个数组
1 2 3 4 5
[root@localhost ~]# echo ${a[*]:0:2} //${数组名[@或*]:起始位置:长度}
1 2
[root@localhost ~]# echo ${a[*]:2:3}
3 4 5
- 数组切换
[root@localhost ~]# a=(1 2 3 4 5)
[root@localhost ~]# echo ${a[*]/4/7} //j将数组a里面的字符4替换成7
1 2 3 7 5
[root@localhost ~]# echo ${a[*]} //并不会替换数组原有内容
1 2 3 4 5
[root@localhost ~]# a=(${a[*]/4/7}) //实现永久替换
[root@localhost ~]# echo ${a[*]}
1 2 3 7 5
- 数组删除
[root@localhost ~]# a=(1 2 3 4 5)
[root@localhost ~]# unset a //删除数组
[root@localhost ~]# echo ${a[*]}
[root@localhost ~]# a=(1 2 3 4 5)
[root@localhost ~]# unset a[2] //删除第三个元素
[root@localhost ~]# echo ${a[*]}
1 2 4 5
3.2 Shell脚本调试
在 Shell 脚本开发中,经常碰到一些规范方面的问题,例如忘了使用引号或在 if 语句末尾处忘记加 fi 结束。要注意把复杂的脚本简单化,要思路清晰,并且分段实现。当执行脚本时出现错误后,不要只看那些提示的错误行,而是要观察整个相关的代码段。
为避免编写的脚本出错,除了在编写脚本时注意书写规范,排除语法错误,更重要的是 利用调试脚本工具来调试脚本。echo 命令是最有用的调试脚本工具之一,一般在可能出现问题的脚本中加入 echo 命令,采用的是分段排查的方式。
- 常用参数的具体含义为:
-n:不会执行该脚本,仅查询脚本语法是否有问题,如果没有语法问题就不显示任 何内容,如果有问题会提示报错。
-v:在执行脚本时,先将脚本的内容输出到屏幕上然后执行脚本,如果有错误,也 会给出错误提示。
-x:将执行的脚本内容输出到屏幕上,这个是对调试很有用的参数。