Linux Shell编程及自动化运维实现 第4章 数组和函数
一、数组
简介
变量:用一个固定的字符串,代替一个不固定字符串。
数组:用一个固定的字符串,代替多个不固定字符串。
类型
普通数组:只能使用整数作为数组索引
关联数组:可以使用字符串作为数组索引
1、普通数组
1、定义普通数组
方法一:
# array2=(tom jack alice)
# array3=(`cat /etc/passwd`) 希望是将该文件中的每一个行作为一个元数赋值给数组array3
# array4=(`ls /var/ftp/Shell/for*`)
# array5=(tom jack alice "bash shell")
# colors=($red $blue $green $recolor)
# array6=(1 2 3 4 5 6 7 "linux shell" [20]=saltstack)
方法二:
数组名[下标]=变量值
# array1[0]=pear
# array1[1]=apple
# array1[2]=orange
# array1[3]=peach
查看数组
[root@localhost ~]# declare -a | grep array1
declare -a array1='([0]="pear" [1]="apache" [2]="orange" [3]="peach")'
查看数组
[root@localhost ~]# echo ${array1[@]}
pear apache orange peach
2、访问普通数组元素
访问数组元数:
# echo ${array1[0]} 访问数组中的第一个元数
# echo ${array1[@]} 访问数组中所有元数 等同于 echo ${array1[*]}
# echo ${#array1[@]} 统计数组元素的个数
# echo ${!array2[@]} 获取数组元素的索引
# echo ${array1[@]:1} 从数组下标1开始
# echo ${array1[@]:1:2} 从数组下标1开始,访问两个元素
2、关联数组
1、定义关联数组
切记:先声明关联数组
# declare -A ass30
方法一
数组名[索引]=变量值
# declare -A ass_array1
# ass_array1[index1]=pear
# ass_array1[index2]=apple
# ass_array1[index3]=orange
# ass_array1[index4]=peach
查看
[root@localhost ~]# echo ${ass_array1[@]}
peach pear apple orange
修改某个值
[root@localhost-111 ~]# unset lol
[root@localhost-111 ~]# declare -A lol
[root@localhost-111 ~]# lol[down1]=aaa
[root@localhost-111 ~]# lol[down2]=bbb
[root@localhost-111 ~]# lol[down3]=ccc
[root@localhost-111 ~]# echo ${lol[@]}
aaa bbb ccc
[root@localhost-111 ~]# lol[down2]=ddd
[root@localhost-111 ~]# echo ${lol[@]}
aaa ddd ccc
方法二
一次赋多个值
# declare -A ass_array2
# ass_array2=([index1]=tom [index2]=jack [index3]=alice [index4]='bash shell')
2、查看数组
# declare -A
declare -A ass_array1='([index4]="peach" [index1]="pear" [index2]="apple" [index3]="orange" )'
declare -A ass_array2='([index4]="bash shell" [index1]="tom" [index2]="jack" [index3]="alice" )'
3、访问数组元素
# echo ${ass_array2[index2]} 访问数组中的第二个元数
# echo ${ass_array2[@]} 访问数组中所有元数 等同于 echo ${array1[*]}
# echo ${#ass_array2[@]} 获得数组元数的个数
# echo ${!ass_array2[@]} 获得数组元数的索引
3、数组和循环
1、通过循环定义和显示数组
2、通过数组统计数据
案例1:while脚本快速定义数组
1、定义数组
#!/bin/bash
#循环读取文件,定义数组
while read line
do
#hosts:数组名
#[++i]:索引递增,++i是1开始,i++是0开始。
#$line:值,即文件中的内容
hosts[++i]=$line
done < /etc/hosts
#输出索引每一行
for i in ${!hosts[@]}
do
echo "$i : ${hosts[$i]}"
done
2、测试数组
[root@localhost ~]# bash array1.sh
“数组hosts first:127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4”
1 : 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
2 : ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
案例2:for脚本快速定义数组
1、定义数组
[root@localhost ~]# vim for_array.sh
#!/bin/bash
#2020
#for array
for line in `cat /etc/hosts`
do
hosts[++i]=$line
done
for i in ${!hosts[@]}
do
echo "$i: ${hosts[$i]}"
done
2、测试数组
[root@localhost ~]# bash for_array.sh
1: 127.0.0.1
2: localhost
3: localhost.localdomain
4: localhost4
5: localhost4.localdomain4
6: ::1
7: localhost
8: localhost.localdomain
9: localhost6
10: localhost6.localdomain6
案例3:数组统计性别
1、定义性别文件
[root@localhost ~]# vim sex.txt
jack m
alice f
tom m
2、定义脚本统计性别
#!/bin/bash
declare -A sex
while read line
do
type=`echo $line|awk '{print $2}'`
let sex[$type]++
done < sex.txt
for i in ${!sex[@]}
do
echo "$i : ${sex[$i]}"
done
3、测试脚本
[root@localhost ~]# bash sex.sh
f : 1
m : 2
案例4:使用数组统计,用户shell的类型和数量
1、示例
declare -A shells
while read ll
do
type=`echo $ll | awk -F: '{print $NF}'`
let shells[$type]++
done < /etc/passwd
for i in ${!shells[*]}
do
echo "$i: ${shells[$i]}"
done
2、验证结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L9L8eQZC-1619003860297)(C:\Users\袁威\AppData\Roaming\Typora\typora-user-images\image-20210421102522753.png)]
二、函数
概念
函数是一段完成特定功能的代码片段(块)
在shell中定义了函数,就可以使代码模块化,便于复用代码
注意函数必须先定义才可以使用。
重点
传参 $1,$2
局部变量 local
返回值 return 即$?
1、定义函数
方法一
函数名() {
函数要实现的功能代码
}
方法二
方法二:
function 函数名 {
函数要实现的功能代码
}
2、调用函数
语法
函数名
函数名 参数1 参数2
三、示例
示例1:初识函数
通过shell脚本,编写系统工具箱
编写循环脚本,功能菜单
provide these tools:
show disk info(d)
show mem info(m)
show cpu info©
quit(q)
#!/bin/bash
show_menu() {
cat << EOF
provide these tools:
show disk info(d)
show mem info(m)
show cpu info(c)
quit(q)
EOF
}
while :
do
show_menu
read -p "Input choice: " choice
case $choice in
d)
echo "===========disk info=============="
df -hT
;;
m)
echo "==========meme info==============="
free -m
;;
c)
echo "==========cpu info================="
uptime
;;
q)
break
;;
*)
show_menu
;;
esac
done
示例2:阶乘函数(传参)
思路:1 了解阶乘概念——>2 定义函数——>3 引用函数
#!/bin/bash
#定义函数名fun1
fun1() {
#定义阶乘元数
factorial=1
#使阶乘循环
for((i=1;i<=5;i++))
do
#阶乘公式
factorial=$[$factorial*$i]
done
#输出阶乘结果
echo “5的阶乘是:$factorial”
}
fun1
优化1:传参,让函数能够自定义 (i<=$1 参数1是阶乘的上限)
#!/bin/bash
fun1() {
factorial=1
for((i=1;i<=$1;i++))
do
factorial=$[$factorial*$i]
done
echo “$1的阶乘是:$factorial”
}
fun1 3
测试脚本
优化2:传参2,由脚本外部传递参数。
#!/bin/bash
fun1() {
factorial=1
for((i=1;i<=$1;i++))
do
factorial=$[$factorial*$i]
done
echo “$1的阶乘是:$factorial”
}
fun1 $1
fun1 $2
fun1 $3
测试:
[root@localhost ~]# bash cc.sh 3 5 10
“3的阶乘是:6”
“5的阶乘是:120”
“10的阶乘是:3628800”
优化3:shell 的写法和其他运算表达式。
#!/bin/bash
fun1() {
factorial=1
#for((i=1;i<=$1;i++))
for i in `seq $1`
do
#factorial=$[$factorial*$i]
#let factorial=$factorial*$i
let factorial*=$i
done
echo “$1的阶乘是:$factorial”
}
fun1 $1
示例3:函数传参 数组传参
1 制作一个简单的阶乘脚本。通过数组给函数传参
#!/bin/bash
#1 先定义一个数组
num=(1 2 3)
#2 定义一个函数
array(){
factorial=1
for i in $* #(重点2)
do
#定义阶层的公式
factorial=$[factorial * $i]
done
echo $factorial
}
#调用函数使用数组(重点1)
array ${num[*]}
2 测试成功。
[root@localhost ~]# ./fun3.sh
6
3 数组的好处在于,多个数组时传参的效率就增高了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8kvUS8ry-1619003860300)(C:\Users\袁威\AppData\Roaming\Typora\typora-user-images\image-20210421190046226.png)]
示例4:函数结果 赋予数组
场景:用户获赠流量包(每人增加5G),结果运算
1 通过函数输出到数组
#!/bin/bash
num=(1 2 3)
array(){
#local定义变量仅在函数中有效。
local j
#设置循环的次数,等于索引总数。
for i in $*
do
#定义不同的值乘以5.注意调取值的时候使用的是索引。
outarray[j++]=$[$i+5]
done
#输出新的数组。
echo "${outarray[*]}"
}
array ${num[*]}
2 测试脚本成功。
[root@localhost ~]# bash function_array.sh
5 10 15
总结:函数不仅可以从数组中调取值,
还可以赋予数组值。
三、影响Shell程序的内置命令
1 概览
:
true
false
exit
break
continue
shift
————————————————————————
shift 使位置参数向左移动,默认移动1位,可以使用shift 2
exit 退出整个程序
bre 结束当前循环,或跳出本层循环
continue 忽略本次循环剩余的代码,直接进行下一次循环
2 continue和break&shift
需求
1 通过循环脚本,输出如下效果。
A123456789
B123456789
...
D123456789
2 编写循环脚本。
#!/bin/bash
for i in {A..D}
do
echo $i
for j in {1..9}
do
echo $j
done
done
3 测试脚本,观察结果(满意否)
[root@localhost ~]# bash for1.sh
A
1
2
3
4
5
6
7
8
9
B
注:因为默认echo输出换行符,使用-n不输出
4 解决换行问题
#!/bin/bash
for i in {A..D}
do
echo -n $i
for j in {1..9}
do
echo -n $j
done
done
5 测试脚本,观察结果(满意否)
[root@localhost ~]# bash for1.sh
A123456789B123456789C123456789D123456789
6 外循环,添加一条空行语句。
#!/bin/bash
for i in {A..D}
do
echo -n $i
for j in {1..9}
do
echo -n $j
done
#空行
echo
done
7 再次测试。完成预期
[root@localhost ~]# bash for1.sh
A123456789
B123456789
C123456789
D123456789
8 总结:循环嵌套的规则是:外部循环一次,内部循环全部。
9 需求:跳出关于5的循环。
[root@localhost ~]# bash for1.sh
A12346789
B12346789
C12346789
D12346789
10 continue登场
if 判断此次循环是否为5,
continue 跳过本次循环。
#!/bin/bash
for i in {A..D}
do
echo -n $i
for j in {1..9}
do
if [ $j -eq 5 ];then
continue
fi
echo -n $j
done
echo
done
11 换成break会怎么样呢?
#!/bin/bash
for i in {A..D}
do
echo -n $i
for j in {1..9}
do
if [ $j -eq 5 ];then
break 2
fi
echo -n $j
done
echo
done
12 测试
[root@localhost ~]# bash for1.sh
A1234
13 课后作业,循环嵌套,打印乘法口诀表。
shift 移动参数
1 for 循环不定义循环范围,循环取参数作为循环范围。
#!/bin/bash
for i
do
let sum+=$i
done
echo "sum : $sum"
测试:
[root@localhost ~]# bash sum.sh
sum :
[root@localhost ~]# bash sum.sh 1
sum : 1
[root@localhost ~]# bash sum.sh 2
sum : 2
[root@localhost ~]# bash sum.sh 3
sum : 3
[root@localhost ~]# bash sum.sh 1 3
sum : 4
2 使用while循环,发现停不下来
#!/bin/bash
while [ $# -ne 0 ]
do
let sum+=$1
echo $sum
done
echo "sum : $sum"
测试:
[root@localhost ~]# bash sum.sh 1 2
根本停不下来。因为循环为真。
3 使用shift 移动参数的命令。结果得以实现。
#!/bin/bash
while [ $# -ne 0 ]
do
let sum+=$1
shift
done
echo "sum : $sum"
测试:
[root@localhost ~]# bash sum.sh 1 2
sum : 3
[root@localhost ~]# bash sum.sh 1 2 3
sum : 6
总结:
shift 1使参数 左移1位,shift 2 左移2位
4 另一个,创建用户的案例。理解参数位移
#!/bin/bash
while [ $# -ne 0 ]
do
useradd $1
echo "$1 is created"
shift
done
测试:
[root@localhost ~]# bash shift_user.sh aa bb
aa is created
bb is created