一: AWK文本处理工具

1.awk基本介绍 ( 编程语言 )


34.shell-awk.html

1.什么是awk

awk不仅仅是一个文本处理工具,通常用于处理数据并生成结果报告。当然awk也是一门编程语言,是linux上功能最强大的数据处理工具之一。

2.awk语法格式 第一种形式

第一种形式:awk ‘BEGIN{} pattern {commands} END {}’ file_name
第二种形式: standard output | awk BEGIN{} pattern {commands} END {}
第三种形式: awk [options] -f awk-script-file filenames

第一种形式:

语法格式 含义
BEGIN {} 正式处理数据之前执行
pattern 匹配模式
{commands} 处理命令,可能多行
END{} 处理完所有匹配数据后执行


在一个文本文件中,提取我们想要的内容,然后进行(输出 精美)

Snipaste_2020-12-11_09-31-34.png
3.awk语法格式分解

  1. #1.首先执行BEGIN中的操作,1/2 =得到0.5
  2. #2.执行 /^root/ pattrn 模式匹配,匹配/etc/passwd 以root开头的行
  3. -root:x:0:0:root:/root:/bin/bash
  4. #3.执行command动作,打印第一列,检查FS是否指定字段分隔符,指定了:为分隔符,那么 $1 则是
  5. -root
  6. #4.执行END中的代码,输出
  7. -oldxu-over
  8. #最终打印出来的结果就是:
  9. -BEGIN 0.5
  10. -pattrn+command root
  11. -END oldxu-over

[root@web01 shell-sed]# cat test.awk

  1. BEGIN{
  2. print 1/2
  3. FS=":"
  4. }
  5. {
  6. print $1
  7. }
  8. END{
  9. print "oldxu-over"
  10. }

[root@web01 shell-sed]# awk -f test.awk /etc/passwd

2.awk工作原理

文字版:

  1. # awk -F: '{print $1,$3}' /etc/passwd
  2. 1.awk将文件中的每一行作为输入, 并将每一行赋给内部变量$0, 以换行符结束
  3. 2.awk开始进行字段分解,每个字段存储在已编号的变量中,从$1开始[默认空格分割]
  4. 3.awk默认字段分隔符是由内部FS变量来确定, 可以使用-F修订
  5. 4.awk行处理时使用了print函数打印分割后的字段
  6. 5.awk在打印后的字段加上空格,因为$1,$3 之间有一个逗号。逗号被映射至OFS内部变量中,
  7. 称为输出字段分隔符, OFS默认为空格.
  8. 6.awk输出之后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符
  9. 串分隔成字段并进行处理。该过程将持续到所有行处理完毕
  10. [root@web01 shell-awk]# #[: ]+
  11. [root@web01 shell-awk]# #1.连续的多个空格算一个
  12. [root@web01 shell-awk]# #2.连续的多个:算一个
  13. [root@web01 shell-awk]# #3. :: 算一个字符

3.awk内置变量(基础)

内置变量 含义
$0 整行内容
$1-$n 当前行的第1-n个字段
NF 当前行的字段个数,也就是多少列
NR 当前的行号,从1开始计数
FS 输入字段分隔符。不指定默认以空格或tab键分割
RS 输入行分隔符。默认回车换行
OFS 输出字段分隔符。默认为空格
ORS 输出行分隔符。默认为回车换行

要想了解awk的一些内部变量需要先准备如下数据文件。

  1. [root@oldxu ~]# cat <<EOF>>awk_file.txt
  2. ll 1990 50 51 61
  3. kk 1991 60 52 62
  4. hh 1992 70 53 63
  5. jj 1993 80 54 64
  6. mm 1994 90 55 65
  7. EOF

_

1.awk内置变量,$0保存当前记录的内容

  1. [root@oldxu ~]# awk '{print $0}' /etc/passwd

_

2.awk内置变量,FS指定字段分割符, 默认以空白行作为分隔符

  1. #1.输出文件中的第一列
  2. [root@oldxu ~]# awk '{print $1}' awk_file.txt
  3. ll
  4. kk
  5. hh
  6. jj
  7. mm
  8. #2.指定多个分隔符,获取第一列内容
  9. [root@oldxu ~]# cat awk_file.txt
  10. ll:1990 50 51 61
  11. kk:1991 60 52 62
  12. hh 1992 70 53 63
  13. jj 1993 80 54 64
  14. mm 1994 90 55 65
  15. #以冒号或空格为分隔符
  16. [root@oldxu ~]# awk -F '[: ]' '{print $2}' awk_file.txt
  17. 1990
  18. 1991
  19. 1992
  20. 1993
  21. 1994
  22. #4.指定多个分隔符
  23. [root@oldxu ~]# cat awk_file.txt
  24. ll::1990 50 51 61
  25. kk:1991 60 52 62
  26. hh 1992 70 53 63
  27. jj 1993 80 54 64
  28. mm 1994 90 55 65
  29. #[: ]+连续的多个冒号当一个分隔符,连续的多个空格当一个分隔符,连续空格和冒号也当做一个字符来处理
  30. [root@oldxu ~]# awk -F '[: ]+' '{print $2}' awk_file.txt
  31. 1990
  32. 1991
  33. 1992
  34. 1993
  35. 1994

3.awk内置变量NF,保存每行的最后一列

  1. #1.通过print打印,NF和$NF,你发现了什么?
  2. [root@oldxu ~]# awk '{print NF,$NF}' awk_file.txt
  3. 5 61
  4. 5 62
  5. 5 63
  6. 5 64
  7. 5 65
  8. #F: 如果将第五行的55置为空,那么该如何在获取最后一列的数字?
  9. [root@oldxu ~]# awk '{print $5}' awk_file.txt
  10. 61
  11. 62
  12. 63
  13. 64
  14. #最后一列为空,为什么?
  15. #Q.使用$NF为什么就能成功?(因为NF变量保存的是每一行的最后一列)
  16. [root@oldxu ~]# awk '{print $NF}' awk_file.txt
  17. 61
  18. 62
  19. 63
  20. 64
  21. 65
  22. #2.如果一个文件很长,靠数列数需要很长的时间,那如何快速打印倒数第二列?
  23. [root@oldxu ~]# awk '{print $(NF-1)}' awk_file.txt
  24. 51
  25. 52
  26. 53
  27. 54
  28. 90


4.awk内置变量NR,表示记录行号。

  1. #1.使用pring打印NR,会发现NR会记录每行文件的行号
  2. [root@oldxu ~]# awk '{print NR,$0}' awk_file.txt
  3. 1 ll 1990 50 51 61
  4. 2 kk 1991 60 52 62
  5. 3 hh 1992 70 53 63
  6. 4 jj 1993 80 54 64
  7. 5 mm 1994 90 65
  8. #2.那如果我们想打印第二行到第三行的内容怎么办?
  9. [root@oldxu ~]# awk 'NR>1&&NR<4 {print NR,$0}' awk_file.txt
  10. 2 kk 1991 60 52 62
  11. 3 hh 1992 70 53 63
  12. #3.那如果只想打印第三行,该怎么办?
  13. [root@oldxu ~]# awk 'NR==3 {print NR,$00}' awk_file.txt
  14. 3 hh 1992 70 53 63
  15. #4.那如果既想打印第三行,又想打印第一列?
  16. [root@oldxu ~]# awk 'NR==3 {print NR,$1}' awk_file.txt
  17. 3 hh

_

5.awk内置变量RS,读入行分隔符。

  1. [root@oldxu ~]# cat file.txt
  2. Linux|Shell|Nginx--docker|Gitlab|jenkins--mysql|redis|mongodb
  3. [root@oldxu ~]# awk 'BEGIN{RS="--"}{print $0}' file.txt
  4. Linux|Shell|Nginx
  5. docker|Gitlab|jenkins
  6. mysql|redis|mongodb

6.awk内置变量,“OFS输出字段分隔符”,初始情况下OFS变量是空格。

  1. [root@oldxu ~]# awk 'BEGIN{RS="--";FS="|";OFS=":"} {print $1,$3}' file.txt
  2. Linux:Nginx
  3. docker:jenkins
  4. mysql:mongodb

7.awk内置变量,“ORS输出行分隔符”,默认行分割符为\n。

[root@openvpn-192 ~]# awk 'BEGIN{RS="--";FS="|";OFS=":";ORS="----"} {print $1,$3}' file.txt
Linux:Nginx----docker:jenkins----mysql:mongodb

内部变量总结

$0: 每行的内容都会 \$0 这个变量
$1 $2 $3 当读入一行内容之后awk会根据分隔符进行自动拆分,并将拆分后的列赋值给
$1$2$3
FS:指定字段分割符,默认为空格。通常我们会根据需求进行修订。-F BEGIN{FS=""}
NF: 当awk通过字段分隔符拆分后,NF会统计拆分后的总列数。
NR:当awk读入一行内容后,会将该内容进行编号,赋值给NR变量。

RS:读入行分隔符,默认是\n,可以通过BEGIN{RS=}进行修订,但一般不做其修改。
OFS:输出字段分割,默认空格,可以修改为任何。BEGIN{OFS=""}
ORS:输出行分割符,默认是\n,可以修改为任意。BEGIN{ORS=“”}

4.Awk格式输出

awk可以通过printf函数生成非常漂亮的数据报表。

格式符 含义
%s 打印字符串
%d 打印十进制数(整数)
%f 打印一个浮点数(小数)
%x 打印十六进制数
修饰符 含义
- 左对齐
+ 右对齐

_

格式输出示例: ** **printf默认没有分隔符。

1.printf默认没有分隔符。
  [root@oldxu ~]# awk 'BEGIN{FS=":"}{printf $1}' /etc/passwd 
  rootbindaemonadm

2.加入换行,格式化输出。
  [root@oldxu ~]# awk 'BEGIN{FS=":"}{printf "%s\n",$1}' /etc/passwd 
  root
  bin
  daemon
  adm

3.使用占位符美化输出。
  [root@oldxu ~]# awk 'BEGIN{FS=":"} {printf "%20s %20s\n",$1,$7}' /etc/passwd
                  root            /bin/bash
                   bin        /sbin/nologin
                daemon        /sbin/nologin
                   adm        /sbin/nologin

4.默认右对齐,- 表示左对齐。
  [root@oldxu ~]# awk 'BEGIN{FS=":"}{printf "%-20s %-20s\n",$1,$7}' /etc/passwd
  root                 /bin/bash           
  bin                  /sbin/nologin       
  daemon               /sbin/nologin       
  adm                  /sbin/nologin

5.美化一个成绩表。
  [root@localhost shell]# cat student.txt
  oldxu       80    90    96    98
  oldqiang    93    98    92    91
  oldguo      78    76    87    92
  oldli       86    89    68    92
  oldgao      85    95    75    90

 #效果
  [root@web01 shell-awk]# cat student.awk
BEGIN {
    printf "%-10s%-10s%-10s%-10s%-10s\n",
    "Name","Yuwen","Shuxue","yinyu","qita"
}

{
    printf "%-10s%-10d%-10d%-10d%-10d\n",$1,$2,$3,$4,$5
}


[root@web01 shell-sed]# awk -f student.awk student.txt
name      Yuwen     shuxue    yinyu     qita
oldxu     80        90        96        98
oldqiang  93        98        92        91
oldguo    78        76        87        92
oldli     86        89        68        92
oldgao    85        95        75        90

5.Awk模式匹配 ( 过滤功能 )

  • awk第一种模式匹配: __RegExp
  • awk第二种模式匹配: __关系运算匹配

_

1.RegExp示例

1.匹配/etc/passwd文件行中含有root字符串的所有行。
-[root@oldxu ~]# awk 'BEGIN{FS=":"}/root/{print $0}' passwd

2.匹配/etc/passwd文件行中以root开头的行。
-[root@oldxu ~]# awk '/^root/{print $0}' passwd

3.匹配/etc/passwd文件行中/bin/bash结尾的行。
-[root@oldxu ~]# awk '/\/bin\/bash$/{print $0}' passwd

**

2.1 比较运算符匹配:

符号 含义
< 小于
> 大于
<= 小于等于
>= 大于等于
== 等于
!= 不等于
~ 匹配正则表达式
!~ 不匹配正则表达式

运算符示匹配例:

1、以:为分隔符,匹配/etc/passwd文件中第3个字段小于50的所有行信息
[root@oldxu ~]# awk 'BEGIN{FS=":"}$3<50{print $0}' passwd

2、以:为分隔符,匹配/etc/passwd文件中第3个字段大于50的所有行信息
[root@oldxu ~]# awk 'BEGIN{FS=":"}$3>50{print $0}' passwd

3、以:为分隔符,匹配/etc/passwd文件中第7个字段为/bin/bash的所有行信息
[root@oldxu ~]# awk 'BEGIN{FS=":"}$7=="/bin/bash"{print $0}' passwd

4、以:为分隔符,匹配/etc/passwd文件中第7个字段不为/bin/bash的所有行信息
[root@oldxu ~]# awk 'BEGIN{FS=":"}$7!="/bin/bash"{print $0}' passwd

5、以:为分隔符,匹配/etc/passwd文件中第3个字段包含3个数字以上的所有行信息
[root@oldxu ~]# awk 'BEGIN{FS=":"}$3 ~ /[0-9]{3,}/{print $0}' passwd

_

2.2 布尔运算符:

符号 含义
||
&&
!


**
布尔运算符匹配示例_**

1、以:为分隔符,匹配passwd文件中包含ftp或mail的所有行信息。
[root@oldxu ~]# awk 'BEGIN{FS=":"}$1=="ftp" || $1=="mail" {print $0}' passwd

2、以:为分隔符,匹配passwd文件中第3个字段小于50并且第4个字段大于50的所有行信息。
[root@oldxu ~]# awk 'BEGIN{FS=":"}$3<50 && $4>50{print $0}' passwd

3.匹配没有/sbin/nologin 的行。
[root@oldxu ~]# awk 'BEGIN{FS=":"} $0 !~ /\/sbin\/nologin/{print $0}' passwd

2.3 运算符匹配

运算符 含义
+
-
*
/
%

_

1、计算学生课程分数平均值,学生课程文件内容如下:
[root@localhost shell]# cat  >student.txt<<-EOF
oldxu       80    90    96    98
oldqiang    93    98    92    91
oldguo      78    76    87    92
oldli       86    89    68    92
oldgao      85    95    75    90
EOF


#1.输出平均值
[root@web01 shell-awk]# cat student.awk
BEGIN {
    printf "%-10s%-10s%-10s%-10s%-10s%-10s\n",
    "Name","Yuwen","Shuxue","yinyu","qita","AVG"
}

{
    total=$2+$3+$4+$5
    avg=total/(NF-1)
}

{
    printf "%-10s%-10d%-10d%-10d%-10d%-10d\n",$1,$2,$3,$4,$5,avg
}


#2.执行观察结果
[root@web01 shell-awk]# awk -f student.awk  student.txt
Name      Yuwen     Shuxue    yinyu     qita      AVG
oldxu     80        90        96        98        91
oldqiang  93        98        92        91        93
oldguo    78        76        87        92        83
oldli     86        89        68        92        83
oldgao    85        95        75        90        86

练习1: 根据要求过考虑

1.找出/etc/passwd文件中uid为0的。
[root@web01 shell-awk]# awk 'BEGIN{FS=":"} $3==0 ' passwd
awk 'BEGIN{FS=":"} $3==0{print $0}'  /etc/passwd

2.找出/etc/passwd文件中uid小于10的用户。
[root@web01 shell-awk]# awk 'BEGIN{FS=":"} $3<10 ' passwd
awk 'BEGIN{FS=":"} $3<10{print $1}' /etc/passwd

3.找出/etc/passwd文件中uid 小于50,且bash为/bin/bash 的行
[root@web01 shell-awk]# awk 'BEGIN{FS=":"} $3<50 && $7="/bin/bash" ' passwd

4.匹配用户名为root并且打印uid小于15的行
[root@web01 shell-awk]# awk 'BEGIN{FS=":"} $1 ~ /root/ && $3<15 ' passwd

5.匹配用户名为root或uid大于5000 ||
[root@web01 shell-awk]# awk 'BEGIN{FS=":"} $1 ~ /root/ || $3>50000 ' passwd

6.匹配uid为3位及以上的行
[root@web01 shell-awk]# awk 'BEGIN{FS=":"} $3 ~ /[0-9]{5,}/ ' passwd

7.匹配到 /sbin/nologin 的行
[root@web01 shell-awk]# awk '/\/sbin\/nologin/' passwd

9.正则匹配nginx开头的行
awk '$0 ~ /^nginx/'

练习2: 解释如下语句含义

awk 示例1

# awk '/west/' datafile
# awk '/^nor/' datafile
# awk '$3 ~ /^nor/' datafile
# awk '/^(no|so)/' datafile
# awk '{print $3,$2}' datafile
# awk '{print $3 $2}' datafile
# awk '{print $0}' datafile
# awk '{print "Number of fields: "NF}' datafile
# awk '/nor/{print $3,$2}' datafile
# awk '/^[ns]/{print $1}' datafile
# awk '$5 ~ /\.[7-9]+/' datafile
# awk '$2 !~ /E/{print $1,$2}' datafile
# awk '$3 ~ /^job/{print $3 "is a nice boy."}' datafile
# awk '$8 ~ /[0-9][0-9]$/{print $8}' datafile
# awk '$4 ~ /Cn$/{print "The price is $" $8 "."}' datafile
# awk '/gdx/{print $0}' datafile
# awk -F: '{print "Number of fields: "NF}' /etc/passwd
# awk -F"[ :]" '{print NF}' /etc/passwd
#先猜结果,然后测试。

awk示例2

[root@oldxu ~]# cat b.txt
oldxu:is a:good boy!

[root@oldxu ~]# awk '{print NF}' b.txt 3
[root@oldxu ~]# awk -F ':' '{print NF}' b.txt 3
[root@oldxu ~]# awk -F"[ :]" '{print NF}' b.txt 5

*6.Awk条件判断

if语句格式: { if (表达式){语句;语句;… }}

1.以:为分隔符,打印当前管理员用户名称
[root@oldxu ~]# awk -F: '{ if($3==0){print $1 "is adminisitrator"} }' /etc/passwd

2.以:为分隔符,统计系统用户数量
[root@oldxu ~]# awk -F: '{ if($3>0 && $3<1000){i++}} END {print i}' passwd

3.以:为分隔符,统计普通用户数量
[root@oldxu ~]# awk -F: '{ if($3>1000){i++}} END {print i}' passwd

4.以:为分隔符,只打印/etc/passwd中第3个字段的数值在50-100范围内的行信息
[root@oldxu ~]# awk 'BEGIN{FS=":"}{if($3>50 && $3<100) print $0}' passwd*

if…
else 语句格式: { if (表达式) {语句;语句;… } else {语句;语句;… }}

#1.以:为分隔符,判断第三列如果等于0,则打印该用户名称,如果不等于0则打印第七列。
[root@oldxu ~]# awk 'BEGIN{FS=":"} { if ($3==0) { print $1 }  else { print $7 }  }' /etc/passwd

#2.以:为分隔符,判断第三列如果等于0,那么则打印管理员出现的个数,否则都视为系统用户,并打印它的个数。
[root@oldxu ~]# awk 'BEGIN{FS=":";OFS="\n"} { if($3==0) { i++ } else { j++ } } END { print i" 个管理员" , j" 个系统用户" }' /etc/passwd
1 个管理员
326 个系统用户

if…
else if…
else 语句格式: { if(表达式 1){语句;语句;… } else if(表达式 2){语句;语句;. .. }else{语句;语句;… }}

1.使用awk if打印出当前/etc/passwd文件管理员有多少个,系统用户有多少个,普通用户有多少个
[root@oldxu ~]# awk -F: '{ if($3==0){i++} else if($3>0 && $3<1000){j++} else if($3>1000) {k++}} END {print "管理员个数"i; print "系统用户个数" j; print "系统用户个 数" }' /etc/passwd
管理员个数1
系统用户个数29
系统用户个数69
[root@web01 shell-awk]# cat passwd_count.awk
#行处理前
BEGIN{
    FS=":";OFS="\n"
}
#行处理中
{
    if($3==0)
        { i++ }
    else if ($3>0 && $3<1001)
        { j++ }
    else
        { k++ }
}
#行处理后
END {
    print i" 个管理员",
          j" 个系统用户",
          k" 个普通用户"
}
2.打印/etc/passwd文件中UID小于50的、或者UID小雨50大于100、或者UID大于100的用户名以及UID。 UID<50    root    0 UID<50    bin    1 50<UID<100    nobody    99 50<UID<100    dbus    81 UID>100    systemd    192 UID>100    chrony    998
[root@oldxu ~]# cat if.awk 
BEGIN{
    FS=":"
}
{
    if($3<50)
    {
        printf "%-20s%-20s%-10d\n","UID<50",$1,$3
    }
    else if ($3>50 && $3<100)
    {
        printf "%-20s%-20s%-10d\n","50<UID<100",$1,$3
    }
    else 
    {
        printf "%-20s%-20s%-10d\n","UID>100",$1,$3
    }
}
3.计算下列每个同学的平均分数,并且只打印平均分数大于90的同学姓名和分数信息
[root@oldxu ~]# cat student.txt
oldxu       80    90    96    98
oldqiang    93    98    92    91
oldguo      78    76    87    92
oldli       86    89    68    92
oldgao      85    95    75    90
[root@oldxu ~]# awk 'BEGIN{printf "%-20s%-20s%-20s%-20s%-20s%-20s\n","Name","Chinese","English","Math","Physical","Average"}{sum=$2+$3+$4+$5;avg=sum/4}{if(avg>90) printf "%-20s%-20d%-20d%-20d%-20d%-0.2f\n",$1,$2,$3,$4,$5,avg}' student.txt


4.统计Nginx的状态,请分别打印出200类、300类、400类、500类的状态码出现了多少次。
200-299: 100次
300-399: 200次
400-499: 100次
500+: 20次

[root@web01 shell-awk]# cat nginx_status.awk
BEGIN {
OFS="\n"
printf "%-10s%-10s\n",
"Status","Count"
}
{
if ($9>=200 && $9<=299)
{ i++ }
else if ($9>=300 && $9<=399)
{ j++ }
else if ($9>=400 && $9<=499)
{ k++ }
else if ($9>=500)
{ l++ }
}
END{
print "200~299: " i,
"300~399: " j,
"400~499: " k,
"500+: " l
}


7.Awk循环语句

while循环:while(条件表达式) 动作

[root@oldxu ~]# awk 'BEGIN{ i=1; while(i<=10){print i; i++} }'
[root@oldxu ~]# awk -F: '{i=1; while(i<=NF){print $i; i++}}' /etc/passwd
[root@oldxu ~]# awk -F: '{i=1; while(i<=10) {print $0; i++}}' /etc/passwd
[root@oldxu ~]#cat b.txt
111 222
333 444 555
666 777 888 999
[root@oldxu ~]# awk '{i=1; while(i<=NF){print $i; i++}}' b.txt

for循环:for(初始化计数器;计数器测试;计数器变更) 动作

#C 风格 for
[root@oldxu ~]# awk 'BEGIN{for(i=1;i<=5;i++){print i} }' 

#将每行打印 10 次
[root@oldxu ~]# awk -F: '{ for(i=1;i<=10;i++) {print $0} }' passwd
[root@oldxu ~]# awk -F: '{ for(i=1;i<=10;i++) {print $0} }' passwd 
[root@oldxu ~]# awk -F: '{ for(i=1;i<=NF;i++) {print $i} }' passwd

需求:计算1+2+3+4+…+100的和,请使用while、for两种循环方式实现
[root@web01 shell-awk]# cat while.awk

# while循环
[root@oldxu ~]# cat add_while.awk 
BEGIN{
    while(i<=100)
    {   # 一个变量不赋值,默认为0或者空
        sum+=i
        i++
    }    
        print sum
}

# for循环 
[root@oldxu ~]# cat add_for.awk 
BEGIN{
    for(i=0;i<=100;i++) 
    {
        sum+=i
    }
        print sum
}


二: AWK数组处理工具

1.AWK数组工具概述

1**.什么是数组**
数组其实也算是变量, 传统的变量只能存储一个值,但数组可以存储多个值。

2**.数组使用场景**
通常用来统计、比如:统计网站访问TOP10、网站Url访问TOP10等等等

3**.**数组统计技巧

1.在awk中,使用数组时,不仅可以使用1 2 3 ..n作为数组索引,也可以使用字符串作为数组索引。 2.要统计某个字段的值,就将该字段作为数组的索引,然后对索引进行遍历。

4.awk数组的语法
array_name[index]=value

5.数组的简单实践案例对比_

shell脚本----------------------------------------------------------------
# for 循环
sum=0
for i in {1..100}
do
    sum=$[ $i + $sum ]    
done
    echo $sum


# while 循环

i=1
sum=0
while [ $i -le 100 ] 
do
    sum=$[ $i + $sum ]    
    let i++
done
    echo $sum


awk脚本----while------------------------------------------------------------
[root@manager awk]# cat test.awk 
BEGIN{
    while (i<=100) {
        sum+=i
        #sum=sum+i
        i++
    }

    print sum
}

awk脚本----for------------------------------------------------------------
BEGIN{
    for(i=0;i<=100;i++) 
    {
        sum=sum+i
    }
        print sum
}

5.1 统计/etc/passwd中各种类型shell的数量。
shell数组:
[root@web01 shell-awk]# cat passwd_count.sh

#!/bin/bash

declare -A hosts
#赋值操作
while read line
do
  types=$(echo $line|awk 'BEGIN{FS=":"} {print $7}')
  let hosts[$types]++

  done</etc/passwd

  #遍历数组
  for item in ${!hosts[@]}
  do
  echo $item,${hosts[$item]}
done

5.1 #awk数组来做:
[root@web01 shell-awk]# awk ‘BEGIN{FS=”:”} {hosts[$NF]++} END { for (item inhosts) { print item,hosts[item]} }’ /etc/passwd

[root@web01 shell-awk]# cat passwd_.awk   #写到到文件中

BEGIN{
FS=":"
}
#赋值操作(因为awk是一行一行读入的,相当是循环了整个文件中的内容){
hosts[$NF]++
}
#赋值完成后,需要通过循环的方式将其索引的次数遍历出来
END {
for (item in hosts) {
print item, #索引名称 /bin/bash /bin/rsync /sbin/nologin
hosts[item] #索引的值 10 20 30 次数
}
}


2.Awk数组案例


access.log
1.模拟生产环境数据脚本,需要跑大约30~60s(等待一段时间ctrl+c结束即可)

[root@localhost shell]# cat insert.sh 
#!/bin/bash
function create_random()
{
    min=$1
    max=$(($2-$min+1))
    num=$(date +%s%N)
    echo $(($num%$max+$min))
}

INDEX=1
while true
do
    for user in oldxu oldguo oldqiang oldboy oldli
    do
        COUNT=$RANDOM
        NUM1=`create_random 1 $COUNT`
        NUM2=`expr $COUNT - $NUM1`
        echo "`date '+%Y-%m-%d %H:%M:%S'` $INDEX user: $user insert $COUNT records into datebase:product table:detail, insert $NUM1 records successfully,failed $NUM2 records" >> ./db.log.`date +%Y%m%d`
        INDEX=`expr $INDEX + 1`
    done
done

需求1:统计每个人分别插入了多少条records进数据库

[root@manager mysql]# cat top1 
{
    # 用户=插入的条目(每一次都不一样,而每一次都会相加)
    insert[$5]+=$7
}

END {
    for ( user in insert ) {

        print user,insert[user]
    }
}

需求2:统计每个人分别插入成功了多少record,失败了多少record

[root@manager mysql]# cat top2 
{
    # 用户=插入的条目(每一次都不一样,而每一次都会相加)
    success[$5]+=$13
    failed[$5]+=$16
}

END {
    for ( user in success ) {

        print user,"成功:"success[user],"失败:"failed[user]
    }
}

_

需求3:将需求1和需求2结合起来,一起输出,输出每个人分别插入多少条数据,多少成功,多少失败,并且要格式化输出,加上标题

[root@manager mysql]# cat top3 
BEGIN {
    printf "%-20s%-20s%-20s%-20s\n",
    "User","Total","Success","Failed"
}

{
    total[$5]+=$7
    success[$5]+=$13
    failed[$5]+=$16
}

END {
    for ( user in success ) {
        printf "%-20s%-20d%-20d%-20d\n",
        user,total[user],success[user],failed[user]
    }
}

需求4:在例子3的基础上,加上结尾,统计全部插入记录数,成功记录数,失败记录数。

[root@lb01 ~]# awk '
BEGIN {
    printf "%-20s%-20s%-20s%-20s\n","User","Total","Success","Failed"
} 
{
    total[$5]+=$7
    success[$5]+=$13
    failed[$5]+=$16

    #在原始数据进行统计累计
    total_sum+=$7
    success_sum+=$13
    failed_sum+=$16  
} 
END { 
    for (u in success) {
    printf "%-20s%-20s%-20d%-20d\n",u,total[u],success[u],failed[u]
    }
    printf "%-20s%-20s%-20d%-20d\n","total",total_sum,success_sum,failed_sum
}' db.log.20191106