Day05-SHELL自动化编程-数组-三剑客进阶
- 14 Shell编程-数组
- 14.1 概述
- 14.2 Shell数组赋值
- 14.3 案例
- 14.4 小结
- 15. Shell-编程-Debug全流程
- 15.1 书写习惯
- 15.2 调试方法
- 16. 再战三剑客
- 16.1 sed与变量
- 16.2 awk
- 1)指哪打哪-案例
- 2)awk的判断与循环
- 3)awk数组
- 17. 总结
14 Shell编程-数组
14.1 概述
-
数组也是一种变量.
-
数组可以存放多个 相关联内容 ,通过访问数组调用结果(值)
-
应用场景:用于存放相关的数据。
-
如何创建数组(手动)
[root@m01 devops-shell]# ip_array=(10.0.0.61 10.0.0.62 10.0.0.63 10.0.0.64)
[root@m01 devops-shell]# echo ${ip_array}
10.0.0.61
[root@m01 devops-shell]# echo ${ip_array[0]}
10.0.0.61
[root@m01 devops-shell]# echo ${ip_array[2]}
10.0.0.63
[root@m01 devops-shell]# echo ${ip_array[*]}
10.0.0.61 10.0.0.62 10.0.0.63 10.0.0.64
[root@m01 devops-shell]# echo ${#ip_array[*]}
4
[root@m01 devops-shell]# for n in ${ip_array[*]}
> do
> echo $n
> done
10.0.0.61
10.0.0.62
10.0.0.63
10.0.0.64
[root@m01 devops-shell]# for((i=0;i<=${#ip_array[*]};i++)) # <=有误
> do
> echo $i ${ip_array[i]}
> done
0 10.0.0.61
1 10.0.0.62
2 10.0.0.63
3 10.0.0.64
4
[root@m01 devops-shell]# for((i=0;i<${#ip_array[*]};i++)); do echo $i ${ip_array[i]}; done
0 10.0.0.61
1 10.0.0.62
2 10.0.0.63
3 10.0.0.64
ip_array数组
ip_array[0] 数组中的某个元素 0表示下标,元素名称
输出数组中所有值
echo ${ip_array[@]}
echo ${ip_array[*]}
计算数组的元素的个数
echo ${#ip_array[@]}
echo ${#ip_array[*]}
课外知识:了解
shell数组,下标或元素名字,默认只能是数字。
要在shell数字中,下标中使用字符串,需要创建关联数组。(awk中使用更多,默认就是这个)
shell数组的循环
推荐的形式
names=(web01 web02 db01 nfs01 backup)
for n in ${names[@]}
do
ping -c 1 -W 1 $n
done
了解的形式
names=(web01 web02 db01 nfs01 backup)
for((i=0;i<${#names[@]};i++))
do
ping -c 1 -W 1 ${names[i]}
done
14.2 Shell数组赋值
shell数组创建(赋值) | 具体形式 | 应用场景 |
---|---|---|
批量直接赋值 | array=(ip01 ip02 ip03 ip04 ) array=( 命令结果 ) # cat ip.txt 三剑客命令获取指定内容 | 应用最多 |
逐个元素赋值 | array[0]=lidao array[1]=oldboy array[2]=oldwang … | 几乎不会使用 |
read命令赋值 | read -p “输入数组中内容:” -a array 可以创建数组,空格分割即可 | 用于连续读取数据,用户输入3个数 |
cat ip.txt
10.0.0.5
10.0.0.6
10.0.0.7
10.0.0.8
10.0.0.9
ip_list=(`cat ip.txt`)
echo ${ip_list[@]}
10.0.0.5 10.0.0.6 10.0.0.7 10.0.0.8 10.0.0.9
echo ${#ip_list[@]}
5
14.3 案例
案例33: 试编写一个Shell程序,该程序能接收用户从键盘输入的10个整数,然后求出其总和、平均值
- 方法00:
- 用户输入数字 10个存放变量中或数组中.
- 存完后,进行计算与统计
[root@m01 devops-shell]# cat 33-calc_num.sh
#!/bin/bash
##############################################################
# File Name:33-calc_num.sh
# Version:V1.0
# Author:oldboy lidao996
# Organization:www.oldboyedu.com
# Desc: 读取用户写入的10个数字,然后计算总和,平均值
##############################################################
tmp_file=${0}_$$.txt
#0.检查输入是否为数字,或q退出
check_num() {
if [ "$num" = "q" ]
then
echo "输入完成,准备进行计算"
break
fi
if [[ ! $num =~ ^[0-9]+$ ]]
then
echo "输入异常,请重新输入数字"
continue
fi
}
#1.死循环读取用户输入,按q退出
read_num() {
while :
do
read -p "请逐个输入数字,完成后按q结束:" num
check_num
#需求向变量中追加内容读取变量内容后写入到文件
echo $num >>$tmp_file
done
}
#2.计算与输出
calc_num() {
num_array=(`cat $tmp_file`)
sum=0
for n in ${num_array[@]}
do
let sum=sum+n
done
#计算平均值
clear
echo "总数:$sum"
echo "平均值:"
echo "$sum/${#num_array[@]}" | bc -l
}
#3.main
main() {
read_num
calc_num
}
main
[root@m01 devops-shell]# sh 33-calc_num.sh
请逐个输入数字,完成后按q结束:1
请逐个输入数字,完成后按q结束:2
请逐个输入数字,完成后按q结束:2
请逐个输入数字,完成后按q结束:3
请逐个输入数字,完成后按q结束:
输入异常,请重新输入数字
请逐个输入数字,完成后按q结束:4
请逐个输入数字,完成后按q结束:44
请逐个输入数字,完成后按q结束:4
请逐个输入数字,完成后按q结束:r
输入异常,请重新输入数字
请逐个输入数字,完成后按q结束:er
输入异常,请重新输入数字
请逐个输入数字,完成后按q结束:ewr
输入异常,请重新输入数字
请逐个输入数字,完成后按q结束:r
输入异常,请重新输入数字
请逐个输入数字,完成后按q结束:wwe
输入异常,请重新输入数字
请逐个输入数字,完成后按q结束:rw
e输入异常,请重新输入数字
请逐个输入数字,完成后按q结束:r
输入异常,请重新输入数字
请逐个输入数字,完成后按q结束:wer
输入异常,请重新输入数字
请逐个输入数字,完成后按q结束:23
请逐个输入数字,完成后按q结束:12
请逐个输入数字,完成后按q结束:q
输入完成,准备进行计算
总数:95
平均值:
10.55555555555555555555
精简版read+awk
[root@m01 /server/scripts/devops-shell]# read -p "请输入数字以空格分割:" num
请输入数字以空格分割:12312 5 56 6 67
[root@m01 /server/scripts/devops-shell]# echo $num|xargs -n1|awk '{sum=sum+$1}END{print sum,sum/NR}'
12446 2489.2
14.4 小结
- 如何赋值(如何创建)(通过命令结果)。
- 如何取值,统计数组元素的个数。
- 数组与for循环。
- 未来常用的是awk数组。
15. Shell-编程-Debug全流程
15.1 书写习惯
书写习惯 |
---|
注释 |
变量 :在脚本中尽量使用变量,变量命名规范(给变量加上说明)。 |
函数 :代码中尽可能使用函数,增加说明。 模块化. |
返回值 : 尽可能增加函数return功能,方便后期调试。 |
参数与选项检查 : 进可能增加exit 返回值的功能,方便后期调试。 |
书写的时候适当增加 输出 :书写代码的时候,可以多写一些echo用于在某些步骤中进行输出。 |
缩进 :代码注意缩进。 |
成对的符号提前输入好. “” [] {} |
15.2 调试方法
调试方法 | 说明 |
---|---|
-x | 大部分时候使用:sh /bash -x显示详细的执行过程。 |
精确显示过程 | 脚本使用functions函数库,脚本过大,可以在脚本中使用 set -x 开始显示详细信息 代码 set +x 关闭显示详细信息 |
注释法 | 使用函数,注释法。注释多余的函数,排除。缩小范围定位问题 |
输出关键变量 | 变量后增加echo输出变量内容。查看过程。 |
-
大部分时候使用:sh -x显示详细的执行过程。
-
排除法
16. 再战三剑客
16.1 sed与变量
案例34-sed命令中如何调用变量
cat ip.txt
10.0.0.5
10.0.0.6
10.0.0.7
10.0.0.8
10.0.0.9
src=10.0.0
dst=172.16.1
sed "s#$src#$dst#g" ip.txt
172.16.1.5
172.16.1.6
172.16.1.7
172.16.1.8
172.16.1.9
16.2 awk
1)指哪打哪-案例
案例35-过滤出/etc/passwd的第2到9行的第1列和第3列
awk -F: 'NR>=2 && NR<=9{print $1,$3}' /etc/passwd
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
案例36-第1列用户名等于root的最后一列(命令解释器)。
awk -F: '$1=="root"{print $NF}' /etc/passwd
/bin/bash
awk -F: '$1==root{print $NF}' /etc/passwd
案例37-进阶:第1列用户名等于root的最后一列(命令解释器)。 使用变量方法
[root@m01 devops-shell]# name=root
[root@m01 devops-shell]# awk -F: -vn=$name '$1==n' /etc/passwd
root:x:0:0:root:/root:/bin/bash
awk -vn=$name '$1==n{print $NF}' /etc/passwd
awk -F: -vn=$name '$1==n{print $NF}' /etc/passwd
awk -F: -vn=$name '$1~n{print $NF}' /etc/passwd
案例38-过滤出网卡文件中ip地址那行
awk -F= '/IPADDR/{print $2}' /etc/sysconfig/network-scripts/ifcfg-eth0
10.0.0.61
2)awk的判断与循环
a)判断(了解)
如果系统根分区磁盘使用率大于80,提示磁盘空间不足
df -h|awk '$NF=="/"{ if($5>=8) print "磁盘空间不足" }'
磁盘空间不足
df -h|awk '$NF=="/"{ if($5>=8) print "磁盘空间不足" }'
awk '$NF=="/"{
if($5>=8)
print "磁盘空间不足"
}'
awk 'NR<=5' /etc/passwd
awk '{if(NR<=5){print $0}}' /etc/passwd
awk '{
if(NR<=5){
print $0
}
}' /etc/passwd
[root@m01 devops-shell]# df -h|awk -F"[ %]+" '$NF=="/"{if($(NF-1)>=5 ) print "磁盘空间不足" }'
磁盘空间不足
[root@m01 devops-shell]# df -h|awk -F"[ %]+" '$NF=="/" && $(NF-1)>=5 { print "磁盘空间不足" }'
磁盘空间不足
b) 循环(了解)
awk 'BEGIN{for(i=1;i<=100;i++) {sum=sum+i} print sum }'
awk 'BEGIN{
for(i=1;i<=100;i++)
{sum=sum+i}
print sum
}'
计算任意数字的总和.
[root@m01 ~]# read -p "请输入数字空格分割:" num
请输入数字空格分割:1 2 4 5 66
[root@m01 ~]# echo $num
1 2 4 5 66
[root@m01 devops-shell]# echo $num |awk '{for(i=1;i<=5;i++) sum=sum+$i ; print sum }'
78
[root@m01 devops-shell]# echo $num |awk '{for(i=1;i<=NF;i++) sum=sum+$i ; print sum }'
78
3)awk数组
a) 概述
-
awk数组专用于统计与分析。
- 去重统计次数(sort+uniq)。
- 去重求和。
-
awk数组与shell数组区别
- awk数组: 关联数组,下标啥都行。
- shell数组:普通数组,下标数字,shell中也有关联数组。
b) 使用
创建
awk 'BEGIN{ array[0]="lidao996";array["lidao"]=996;array[110]="sos" }'
取值
[root@oldboy-devops-shell ~]# awk 'BEGIN{
array[0]="lidao996";
array["lidao"]=996;
array[110]="sos";
print array[0]
}'
lidao996
[root@oldboy-devops-shell ~]# awk 'BEGIN{
array[0]="lidao996";
array["lidao"]=996;
array[110]="sos";
print array["lidao"]
}'
996
[root@m01 devops-shell]# awk 'BEGIN{ array[0]="lidao";array["boss"]="oldboy";print array[0] }'
lidao
[root@m01 devops-shell]# awk 'BEGIN{ array[0]="lidao";array["boss"]="oldboy";print array[0],array["boss"] }'
lidao oldboy
[root@m01 devops-shell]# awk 'BEGIN{ array[0]="lidao";array["boss"]="oldboy"; for( n in array ) print n }'
boss
0
[root@m01 devops-shell]# awk 'BEGIN{ array[0]="lidao";array["boss"]="oldboy"; for( n in array ) print n,array[n] }'
boss oldboy
0 lidao
循环(专用循环)
awk专用于数组的循环
for(n in 数组名字)
print n(数组下标),数组名字[n]
awkfor循环 数组专用循环
变量n,获取数组下标
数组名字[下标]才是对应的值
awk 'BEGIN{
arr
for (n in array)
print n,array[n]
}'
110 sos
0 lidao996
lidao 996
c) 案例
批量赋值
cat awk-array.txt
img.oldboylinux.cn 6
bbs.oldboylinux.cn 7
avi.oldboylinux.cn 99
mp4.oldboylinux.cn 88
要求:
1.创建以url为下标,元素值是次数数组。输出数组内容。
[root@m01 devops-shell]# cat /server/files/awk_array.txt
img.oldboylinux.cn 6
bbs.oldboylinux.cn 7
avi.oldboylinux.cn 99
mp4.oldboylinux.cn 88
[root@m01 devops-shell]# awk '{ array[$1]=$2 }END{ for( n in array )print n,array[n] }' /server/files/awk_array.txt
img.oldboylinux.cn 6
avi.oldboylinux.cn 99
bbs.oldboylinux.cn 7
mp4.oldboylinux.cn 88
[root@m01 devops-shell]# awk '{ array[$1]=$2 }END{ for( n in array )print n,array[n] }' /server/files/awk_array.txt|sort -rnk2
avi.oldboylinux.cn 99
mp4.oldboylinux.cn 88
bbs.oldboylinux.cn 7
img.oldboylinux.cn 6
案例39-去重统计次数
分析文件中每个域名出现的次数
cat /server/files/url.txt
http://www.etiantian.org/index.html
http://www.etiantian.org/1.html
http://post.etiantian.org/index.html
http://mp3.etiantian.org/index.html
http://www.etiantian.org/3.html
http://post.etiantian.org/2.html
[root@m01 devops-shell]# awk -F"[/.]+" '{ array[$2]=array[$2]+1 }END{ for( n in array )print n,array[n] }' /server/files/url.txt
www 3
mp3 1
post 2
[root@m01 devops-shell]# awk -F"[/.]+" '{ array[$2]++ }END{ for( n in array )print n,array[n] }' /server/files/url.txt
www 3
mp3 1
post 2
统计ip地址访问次数。
awk '{url[$1]Վҡ}END{ for(name in url )print name,url[name]}' access.log |sort -rnk2 |head
案例40-统计access.log中每个ip地址的流量总数。
第1列是ip地址
第10列是流量(单位是字节)
[root@m01 devops-shell]# awk '{ array[$1]=array[$1]+$10 }END{ for( n in array )print n,array[n] }' /server/files/access.log |sort -rnk2|head
157.55.39.187 1254922
117.63.25.97 446568
47.103.21.203 179675
47.103.14.133 173519
106.14.11.104 171321
207.46.13.186 156643
207.46.13.90 104867
61.147.15.67 95592
157.55.39.4 89426
83.97.20.34 85840
[root@m01 devops-shell]# awk '{ array[$9]=array[$9]+$10 }END{ for( n in array )print n,array[n] }' /server/files/access.log |sort -rnk2|head
200 2805703
302 588708
404 106083
400 7494
301 75
Vezir.04 0
SP1 0
499 0
150 0
"-" 0
本质:ip地址是一样的然后把第10列相加。
本质: 最后输出结果
# i=i+1 == i++
# sum=sum+xxx
# array[$1]=array[$1]+1 == array[$1]++
# array[$1]=array[$1]+$10
awk与shell语法格式对比
具体语法 | awk | shell编程 |
---|---|---|
if单分支判断 | if (条件) {命令 多个命令} | if 条件;then 命令 fi |
if双分支判断 | if (条件) {命令} else {命令} | if 条件;then 命令 else 命令 fi |
for循环:c语言形式 | for(i=1;i<=10;i++) {命令} | for(i=1;i<=10;i++) do {命令} done |
for循环:通用 | awk专用于数组的循环 for( n in 数组名字) print n(数组下标),数组名字[n] | for n in 清单 do {命令} done |
17. 总结
- shell编程环境
- shell执行方式sh/bash
- 变量取值,赋值,命名.
- 普通变量${} ,环境变量(了解)
- 案例-登录系统后输出基本信息。
- 特殊变量 $n, 0 , 0, 0,#,$?
- 其他特殊变量:能够认识,知晓含义即可.
- 今日案例:多种命令,多种传参方式实现计算器