一、case多分支语句
1.1、case语句的结构
- 针对变量的不同取值,分别执行不同的命令序列
- 这种情况与多分支的if语句非常相似,只不过if语句需要判断多个不同的条件,而case语句指示判断一个变量的不同取值
格式:
case 变量值 in
模式1)
命令序列1
;;
模式2)
命令序列2
;;
....
*)
默认命令序列
esac
例:
实例:
case 控制指令 in
start)
启动XX服务
;;
stop)
停止XX服务
;;
....
*)
显示服务脚本的用法
esac
1.2、case语句的实例
1.2.1、创建一个判断输入类型的脚本
- 提示用户输入一个字符
- 判断出该字符是字母,数字或者其他字符
[root@localhost opt]# vim panduan.sh
#!/bin/bash
read -p "请输入一个字符:" aa
case "$aa" in
[0-9])
echo "你输入的是数字"
;;
[a-z]|[A-Z])
echo "你输入的是字母"
;;
*)
echo "你输入的是符号"
esac
~
[root@localhost opt]# chmod +x panduan.sh
[root@localhost opt]# ./panduan.sh
请输入一个字符:3
你输入的是数字
[root@localhost opt]# ./panduan.sh
请输入一个字符:e
你输入的是字母
[root@localhost opt]# ./panduan.sh
请输入一个字符:#
你输入的是符号
1.2.2、判断学生成绩的优良
成绩0-100分
0-59分:不及格
60-74:及格
75-84:良好
85-100:优秀
[root@localhost opt]# vim chengji.sh
#!/bin/bash
read -p "请输入你的成绩:" aa
case "$aa" in
#[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])
[1-5][0-9]|[0-9])
echo "你的成绩不合格"
;;
6[0-9]|7[0-4])
echo "你的成绩合格"
;;
7[5-9]|8[0-4])
echo "你的成绩良好"
;;
8[5-9]|9[0-9]|100)
echo "你的成绩优秀"
;;
*)
echo "输入有误"
esac
~
[root@localhost opt]# ./chengji.sh
请输入你的成绩:0
你的成绩不合格
[root@localhost opt]# ./chengji.sh
请输入你的成绩:59
你的成绩不合格
[root@localhost opt]# ./chengji.sh
请输入你的成绩:60
你的成绩合格
[root@localhost opt]# ./chengji.sh
请输入你的成绩:74
你的成绩合格
[root@localhost opt]# ./chengji.sh
请输入你的成绩:75
你的成绩良好
[root@localhost opt]# ./chengji.sh
请输入你的成绩:84
你的成绩良好
[root@localhost opt]# ./chengji.sh
请输入你的成绩:85
你的成绩优秀
[root@localhost opt]# ./chengji.sh
请输入你的成绩:100
你的成绩优秀
[root@localhost opt]# ./chengji.sh
请输入你的成绩:101
输入有误
[root@localhost opt]# ./chengji.sh
请输入你的成绩:-1
输入有误
二、循环语句
2.1、for循环
2.1.1、for语句结构
- 读取不同的变量值,用来逐个执行同一组命令
语句结构
for 变量名 in 取值列表
do
命令序列
done
语句结构举例
for 收件人 in 邮件地址列表
do
发送邮件
done
2.1.2、使用for批量添加用户
- 用户名存放在users.txt文件中,每行一个
- 初始密码均设为123456
[root@localhost opt]# vim user.txt
zhangsan
lisi
wangermazi
zhaoliu
tianji
wangba
[root@localhost opt]# vim useradd.sh
#!/bin/bash
Lists=$(cat /opt/user.txt)
for bb in $Lists
do
useradd $bb
echo "123456" | passwd --stdin $bb
echo "$bb添加成功"
done
[root@localhost opt]# chmod +x useradd.sh
[root@localhost opt]# ./useradd.sh
Changing password for user zhangsan.
passwd: all authentication tokens updated successfully.
zhangsan添加成功
useradd: warning: the home directory already exists.
Not copying any file from skel directory into it.
Creating mailbox file: File exists
Changing password for user lisi.
passwd: all authentication tokens updated successfully.
lisi添加成功
Changing password for user wangermazi.
passwd: all authentication tokens updated successfully.
wangermazi添加成功
Changing password for user zhaoliu.
passwd: all authentication tokens updated successfully.
zhaoliu添加成功
Changing password for user tianji.
passwd: all authentication tokens updated successfully.
tianji添加成功
Changing password for user wangba.
passwd: all authentication tokens updated successfully.
wangba添加成功
[root@localhost opt]# cat /etc/passwd | grep "bash"
root:x:0:0:root:/root:/bin/bash
dd:x:1000:1000:cn-tangzheng:/home/dd:/bin/bash
zhangsan:x:1001:1001::/home/zhangsan:/bin/bash
lisi:x:1002:1002::/home/lisi:/bin/bash
wangermazi:x:1003:1003::/home/wangermazi:/bin/bash
zhaoliu:x:1004:1004::/home/zhaoliu:/bin/bash
tianji:x:1005:1005::/home/tianji:/bin/bash
wangba:x:1006:1006::/home/wangba:/bin/bash
脚本可以适当修改优化:如
echo "123456" | passwd --stdin $bb &> /dev/null
批量删除用户:在刚刚的基础上修改
[root@localhost opt]# vim useradd.sh
#!/bin/bash
Lists=$(cat /opt/user.txt)
for bb in $Lists
do
userdel -r $bb '-r 删除家目录'
#echo "123456" | passwd --stdin $bb &> /dev/null
echo "$bb删除成功"
done
[root@localhost opt]# ./useradd.sh
zhangsan删除成功
lisi删除成功
wangermazi删除成功
zhaoliu删除成功
tianji删除成功
wangba删除成功
[root@localhost opt]# cat /etc/passwd | grep "bash"
root:x:0:0:root:/root:/bin/bash
dd:x:1000:1000:cn-tangzheng:/home/cn-tangzheng:/bin/bash
2.1.3、shell-let命令
- let 对整数进行数学运算
- let和双小括号 (( )) 一样,let 命令也只能进行整数运算,不能对小数(浮点数)或者字符串进行运算。
语法格式
let 表达式
或
let "表达式"
或
let '表达式'
以上方式都等价于 ((表达式))
- 当表达式中含有 Shell 特殊字符(例如 |)时,需要用双引号" "或者单引号’ '将表达式包围起来。
- 和 (( )) 类似,let 命令也支持一次性计算多个表达式,并且以最后一个表达式的值作为整个 let 命令的执行结果。
2.1.4、计算1-10偶数/奇数的和
- 方式一:计算偶数的和
#!/bin/bash
sum=0
for((i=0;i<=10;i+=2))
do
let sum+=$i
done
echo "总和为:$sum"
- 方式一:计算奇数的和
#!/bin/bash
sum=0
for((i=1;i<=10;i+=2))
do
let sum+=$i
done
echo "总和为:$sum"
- 方式二:求偶数和
#!/bin/bash
sum=0
for((i=0;i<=10;i+=2))
do
if [ `expr $i % 2` -eq 0 ]
then
let sum+=$i
fi
done
echo "总和为:$sum"
- 方式二:求奇数和
#!/bin/bash
sum=0
for((i=1;i<=10;i+=2))
do
if [ `expr $i % 2` -eq 1 ]
then
let sum+=$i
fi
done
echo "总和为:$sum"
2.2、while循环语句
2.2.1、while语句结构
- 重复测试某个条件,只要条件成立则反复执行
语句结构
while 条件测试操作
do
命令序列
done
语句结构示例
while 未猜中正确的价格
do
反复猜测商品价格
done
2.2.2、while语句应用示例
- 使用while循环语句输出1-10数字
#!/bin/bash
i=0
while [ $i -le 5 ]
do
echo "$i"
let i++
done
[root@localhost opt]# . cccc.sh
0
1
2
3
4
5
2.2.3、while死循环
- while true:死循环有时候也有奇效,可与用户交互
#!/bin/bash
while true
do
read -p "请输入yes退出:" KEY
if [ $KEY = yes ]
then
break
fi
done
echo "正常退出"
[root@localhost opt]# ./sixunhuan.sh
请输入yes退出:no
请输入yes退出:1
请输入yes退出:d
请输入yes退出:!
请输入yes退出:a
请输入yes退出:yes
正常退出
2.2.4、使用while批量添加用户
- 用户名称以stu开头,按数字顺序进行编号
- 一共添加20个用户,即stu1,stu2…stu20
- 初始密码设置为
#!/bin/bash
i=0
while [ $i -le 19 ]
do
let i++
useradd stu$i
echo "123456" | passwd --stdin stu$i &> /dev/null
echo "stu$i添加成功"
done
echo "添加完毕"
[root@localhost opt]# ./useradd.sh
stu1添加成功
stu2添加成功
stu3添加成功
stu4添加成功
stu5添加成功
stu6添加成功
stu7添加成功
stu8添加成功
stu9添加成功
stu10添加成功
stu11添加成功
stu12添加成功
stu13添加成功
stu14添加成功
stu15添加成功
stu16添加成功
stu17添加成功
stu18添加成功
stu19添加成功
stu20添加成功
添加完毕
2.2.5、猜商品价格游戏
- 通过变量RANDOM获得随机数
- 提示用户猜测并记录次数,猜中后退出循环
#!/bin/bash
A=`expr $RANDOM % 1000`
i=0
echo "商品的实际价格为0-999之间,猜猜看是多少?"
read -p "请输入你猜测的价格数目:" num
while [ $num -le 999 ] && [ $num -ge 1 ]
do
let i++
if [ $num -eq $A ]
then
echo "恭喜你答对了,实际价格是$A"
echo "你一共猜测了$i 次"
exit 0
elif [ $num -lt $A ]
then
echo "太低了"
read -p "请输入你猜测的价格数目:" num
else
echo "太高了"
read -p "请输入你猜测的价格数目:" num
fi
done
2.3、continue和break
2.3.1、continue
命令格式: continue n
n 表示循环的层数:
如果省略 n,则表示 continue 只对当前层次的循环语句有效,遇到 continue 会跳过本次循环,忽略本次循环的剩余代码,直接进入下一次循环。
如果带上 n,比如 n 的值为 2,那么 continue 对内层和外层循环语句都有效,不但内层会跳过本次循环,外层也会跳过本次循环,其效果相当于内层循环和外层循环同时执行了不带 n 的 continue。这么说可能有点难以理解,稍后我们通过代码来演示。
continue 关键字也通常和 if 语句一起使用,即满足条件时便跳出循环。
2.3.2、break
命令格式: break n
n 表示跳出循环的层数,如果省略 n,则表示跳出当前的整个循环。
break 关键字通常和 if 语句一起使用,即满足条件时便跳出循环。
2.3.3、break和continue的区别
- break 用来结束所有循环,循环语句不再有执行的机会;continue 用来结束本次循环,直接跳到下一次循环,如果循环条件成立,还会继续循环。
2.4、untli循环语句
2.4.1、until语句的结构
- 重复测试某个条件,只要条件不成立则反复执行
until 条件测试操作
do
命令序列
done
while 未超过10
do
数字依次增加
done
2.4.2、until语句应用1
- 计算1–50的和
通过循环累加的方式计算1–50的和
#!/bin/bash
i=1
S=0
until [ $i -eq 51 ]
do
let S+=$i
let i++
done
echo "$S"
[root@localhost opt]# ./jisuan.sh
1275
2.4.3、until语句应用2
- 为指定用户发送在线消息
1、若指定用户不在线(未登陆系统),则每10分钟(实验中为了测试效果,可改为3s)试一次,直至用户登录系统后再发送信息
2、用户名与消息通过为止参数传递给脚本
#!/bin/bash
username=$1
#判断格式参数是否为空
if [ $# -lt 1 ]
then
echo "Usage:`basename $0` <username> [<message>]"
exit 1
fi
#判断账号是否存在
if grep "^$username:" /etc/passwd &> /dev/nell;then :
else
echo "用户不存在"
exit 2
fi
#判断用户是否在线
until who | grep "$username" &> /dev/null
do
echo "用户不在线,正在尝试连接"
sleep 3
done
mes=$*
echo "$mes" | write "$username"
[root@localhost opt]# ./mes.sh
Usage:mes.sh <username> [<message>]
[root@localhost opt]# ./mes.sh wangwu
用户不存在
[root@localhost opt]# ./mes.sh stu1
用户不在线,正在尝试连接
用户不在线,正在尝试连接
三、shell函数
Shell 函数的本质是一段可以重复使用的脚本代码,这段代码被提前编写好了,放在了指定的位置,使用时直接调取即可。
Shell 中的函数和C++、Java、Python、C# 等其它编程语言中的函数类似,只是在语法细节有所差别。
Shell 函数定义的语法格式如下:
function name() {
statements
[return value]
}
对各个部分的说明:
function
是 Shell 中的关键字,专门用来定义函数;name
是函数名;statements
是函数要执行的代码,也就是一组语句;return value
表示函数的返回值,其中 return 是 Shell 关键字,专门用在函数中返回一个值;这一部分可以写也可以不写。
由{ }
包围的部分称为函数体,调用一个函数,实际上就是执行函数体中的代码。
3.1、 函数定义的简化写法
如果你嫌麻烦,函数定义时也可以不写 function 关键字:
name() {
statements
[return value]
}
如果写了 function 关键字,也可以省略函数名后面的小括号:
function name {
statements
[return value]
}
我建议使用标准的写法,这样能够做到“见名知意”,一看就懂。
[root@localhost opt]#vim jia.sh
#!/bin/bash
sum(){
#命令序列
s=`expr 2 + 2`
echo $s
}
sum
~
[root@localhost opt]# sh jia.sh
4
#!/bin/bash
sum(){
#命令序列
s=`expr $1 + $2`
echo $s
}
sum 2 3
[root@localhost opt]# sh xia.sh
5
#!/bin/bash
sum(){
#命令序列
# k=`expr $1 + $2` #这里注释一下
# echo $k
return $(($1 + $2))
}
sum 2 3
#res=$(sum 2 3)
echo $?
~
[root@localhost opt]# sh xia.sh
5
把return 返回的值调出来了
#!/bin/bash
sum(){
#命令序列
# k=`expr $1 + $2`
# echo $k
echo $(($1 + $2))
}
#sum 2 3
res=$(sum 2 3)
echo $?,$res
[root@localhost opt]# sh xia.sh
0,5
#!/bin/bash
sum(){
#命令序列
# k=`expr $1 + $2`
# echo $k
return $(($1 + $2)) #把echo换成return
}
#sum 2 3
res=$(sum 2 3)
echo $?,$res
~
[root@localhost opt]# sh xia.sh
5,
#!/bin/bash
#求和函数体
function sum(){
#命令序列
read -p "请输入第一个整数: " num1
read -p "请输入第一个整数: " num2
SUM=$[$num1+$num2]
echo "和:$SUM"
}
sum
[root@localhost opt]# sh 3.sh
请输入第一个整数: 3
请输入第一个整数: 4
和:7
#!/bin/bash
#求和函数体
function sum(){
#命令序列
read -p "请输入第一个整数: " num1
read -p "请输入第一个整数: " num2
SUM=$[$num1+$num2]
echo $SUM
return 50
}
shuai=`sum`
echo $?
echo $shuai
[root@localhost opt]# sh 5.sh
请输入第一个整数: 3
请输入第一个整数: 4
50
7
#!/bin/bash
#求和函数体
function sum(){
#命令序列
#read -p "请输入第一个整数: " num1
#read -p "请输入第一个整数: " num2
SUM=$[$1+$2]
#echo 返回的是处理结果值
echo $SUM
#return返回的是状态码
return 50
}
shuai=`sum 3 4`
let shuai+=1
echo $shuai
[root@localhost opt]# sh 6.sh
8
3.2、 函数的作用范围
- 函数在Shell脚本中仅在当前Shell环境中有效
- ShelI脚本中变量默认全局有效
- 将变量限定在函数内部使用local命令
示例
●函数内部变量通过local来实现
◆通过定义myfun函数,在其内部设置局部变量i
◆函数内部和外部分别赋值,进行结果验证
#!/bin/bash
function shu(){
read -p "请输入第一个整数:" num1
read -p "请输入第一个整数:" num2
shuai=$[$num1+$num2]
ai=50
echo "函数内$ai"
echo "和:$shuai"
}
shu
echo "函数外$ai"
[root@localhost opt]# sh 7.sh
请输入第一个整数:3
请输入第一个整数:4
函数内50
和:7
函数外50
[root@localhost opt]# sh 7.sh
请输入第一个整数:3
请输入第一个整数:4
函数内50
和:7
函数外
3.3、 递归函数
调用自己本身的函数
示例
递归遍历目录
通过定义递归函数list_files来实现
#!/bin/bash
function list_files(){
for s in `ls $1`
do
#判断是否为目录
if [ -d "$1/$s" ]
then
echo "$2$s"
#递归调用
list_files "$1/$s" " $2"
else
echo "$2$s"
fi
done
}
list_files "/var/log" ""
'$1表示/var/log' 集合
'$s表示/var/log下的一个目录'
'$2表示指定格式 子目录一定要做一个首行缩进
[root@localhost opt]# bash di.sh
anaconda
anaconda.log
ifcfg.log
journal.log
ks-script-SbAyfV.log
packaging.log
program.log
storage.log
syslog
X.log
audit
....省略诶容
四、shell数组
4.1、 应用场景包括
- 应用场景包长度
- 获取数组长度
- 获取元素长度
- 遍历元素
- 元素切片
- 元素替换
- 元素删除
- …
4.2、 数组的描述
数组:放着相同类型的数据集合
应用场景比较多:列如班级人的成绩跟名字
[11,22,33,44] 在内存中开辟了连续的空间
配合循环使用
数组名称arr arr=(11,22,33,44)
数组元素: 11 22 33 44都是
数组的长度: arr有4 个元素
数组下标:33元素的下面是2 (比如11下标是0 22下标是1)
for 临时标量 in 数组
do
done
4.3、 数组定义方法
方法一
数组名=(shuai0 shuai1 shuai2...)
示例
[root@localhost opt]# num=(11 22 33 44) '定义数组 元素直接一定要有空格'
[root@localhost opt]# echo $num '单独输出是输出不了全部元素的'
11
[root@localhost opt]# echo ${num[*]} '*代表所有'
11 22 33 44
[root@localhost opt]# echo ${num[3]} '把*换成第几个下标就是输出第几个元素'
44
方法二
数组名=([0]=shuai [1]=shuai [3]=shuai..)
示例
[root@localhost opt]# num=([0]=11 [1]=22 [2]=33 [3]=44)
[root@localhost opt]# echo ${num[@]} '@作用跟*一样'
11 22 33 44
[root@localhost opt]# echo ${num[*]}
11 22 33 44
方法三
列表名="shuai0 shuai1 shuai2.."
数组名= ($列表名)
示例
[root@localhost opt]# shuai="12 13 14 15"
[root@localhost opt]# num=($shuai)
[root@localhost opt]# echo ${num[*]}
12 13 14 15
[root@localhost opt]# vim test.txt '在test.txt文件写入数字'
[root@localhost opt]# cat test.txt '查看一下'
11
22
33
44
55
[root@localhost opt]# vim test.sh
#!/bin/bash
list=`cat test.txt`
shuai=($list)
echo ${shuai[*]}
[root@localhost opt]# sh test.sh
11 22 33 44 55
方法三
往往做的是替换 替换某一个元素
数组名[0]="shuai"
数组名[1]="shuai"
数组名[2]="shuai"
[root@localhost opt]# echo ${num[*]}
12 13 14 15
[root@localhost opt]# num[1]=88
[root@localhost opt]# echo ${num[*]}
12 88 14 15
4.3.1、 创建1到100数组
#!/bin/bash
for ((i=0;i<=99;i++));do
shuai[$i]=$[$i+1]
done
echo ${shuai[*]}
[root@localhost opt]# sh 5.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
4.3.2、 创建1到100奇数组
#!/bin/bash
for ((i=0;i<=99;i+=2));do
shuai[$i]=$[$i+1]
done
echo ${shuai[*]}
[root@localhost opt]# sh 5.sh
1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 53 55 57 59 61 63 65 67 69 71 73 75 77 79 81 83 85 87 89 91 93 95 97 99
1-100其中的奇数
下标 0 1 2 3 4 5 定义i
元素 1 3 5 7 9 11 定义k i + i+ i+j
增量 1 2 3 4 5 6 定义j
方法2
#!/bin/bash
#创建1-100奇数的数组
k=0 #定义元素
j=1 #定义增量
for ((i=0;i<=100;i++));do
k=$[$i+$j]
let j++
#最大元素不能超过100
if [ $k -le 100 ];then
shuai[$i]=$k
fi
done
echo ${shuai[@]}
4.3.3、 创建任意数字及长度,根据客户需求加入元素
#!/bin/bash
i=0
while true
do
read -p "是否加入元素(yes/no):" dd
if [ $dd == "no" ];then
break
fi
read -p "请存入第$[$i+1]个元素:" tt
shuai[$i]=$tt
let i++
done
echo ${shuai[@]}
[root@localhost opt]# sh xx.sh
是否加入元素(yes/no):yes
请存入第1个元素:23
是否加入元素(yes/no):yes
请存入第2个元素:45
是否加入元素(yes/no):yes
请存入第3个元素:56
是否加入元素(yes/no):no
23 45 56
4.4、 数组操作
4.4.1、 获取数组长度
[root@localhost opt]# abc=(11 22 33)
[root@localhost opt]# echo ${abc[*]}
11 22 33
[root@localhost opt]# echo ${abc[2]}
33:
4.4.2、 读取某下标赋值
[root@localhost opt]# num=([0]=11 [1]=22 [2]=33 [3]=44)
[root@localhost opt]# echo ${num[0]}
11
[root@localhost opt]# echo ${num[2]}
33
[root@localhost opt]# echo ${num[3]}
44
4.4.3、 一组值,从不满60加到60
#!/bin/bash
#原始数据
num=(56 90 59 53 89)
#遍历数组
for ((i=0;i<${#num[*]};i++));do
#判断是否大于60,为满足60直接赋值60
if [ ${num[$i]} -lt 60 ];then
new[$i]=60
else
new[$i]=${num[$i]}
fi
done
echo ${new[*]}
[root@localhost opt]# bash 60.sh
60 90 60 60 89
4.4.4、 求数组的最大值
#!/bin/bash
num=(89 96 35 73)
shuai=0
for ((i=0;i<${#num[*]};i++));do
#比较大小,大的赋予给shuai
if [ ${num[$i]} -gt $shuai ];then
shuai=${num[$i]}
fi
done
echo $shuai
[root@localhost opt]# sh 61.sh
96
满60加到60
#!/bin/bash
#原始数据
num=(56 90 59 53 89)
#遍历数组
for ((i=0;i<${#num[*]};i++));do
#判断是否大于60,为满足60直接赋值60
if [ ${num[$i]} -lt 60 ];then
new[$i]=60
else
new[$i]=${num[$i]}
fi
done
echo ${new[*]}
[root@localhost opt]# bash 60.sh
60 90 60 60 89
4.4.5、 求数组的最大值
#!/bin/bash
num=(89 96 35 73)
shuai=0
for ((i=0;i<${#num[*]};i++));do
#比较大小,大的赋予给shuai
if [ ${num[$i]} -gt $shuai ];then
shuai=${num[$i]}
fi
done
echo $shuai
[root@localhost opt]# sh 61.sh
96
感谢观看,不足之处多多指教