第三节 awk

一、awk 

1.简介

AWK是一种处理文本文件的语言,是一个强大的文本分析工具。

之所以叫AWK是因为其取了三位创始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的Family Name的首字符。

2.awk的工作原理

awk读入一行,执行一次括号里面的动作

3.awk的语法格式

(1)#awk 选项    'BEGIN{}  {}  END{}'    文件

由BEGIN和END两个特殊例程和{}主输入循环组成

BEGIN和END过程是可选的。

# awk ‘BEGIN {print “hello,World”}’

Hello,World

(2)BEGIN{}

BEGIN{} 所有文本内容读入之前要执行的命令

BEGIN模式不需要等待输入,它在第一个输入行读入之前执行。

(3){ }主输入循环

{} 主输入循环 用的最多

(4)END{ }

END{} 所有文本全部读入完成之后执行的命令

4.print

(1)不跟任何参数,打印awk读入的内容,一行一行读入

(2)跟参数:

数字         不要加引号   ------>print  5      "5"----代表字符串

字符串      必须加引号  ------->print  "a"

变量          没有加引号的字符串   -------->print   a

5.模式匹配

#cat src1.awk
/[0-9]+/ { print "That is an integer" }
/[A-Za-z]+/ { print "This is a string" }
/^$/ { print "This is a blank line." }

一个特殊的例子:一行文本可以匹配一条或多条规则
# echo 4t | awk -f src1.awk
That is an integer
This is a string

6.记录和字段

awk假设它的输入是有结构的,而不是一串无规则的字符。默认它将每个输入行作为一条记录,而将由空格或制表符分隔的单词作为字段。(连续的多个空格和/或制表符被作为一个分隔符)

(1)记录(record):

以记录分割符分割的字符串

(2)字段(  field  [fi:ld]):

以字段分割符分割的字符串,(在一条记录里,被字段分隔符隔开的就是分别的两个字段)                              

字段包括在记录里面

(3)分隔符(separate[ˈseprət])

默认记录分隔符:  \n

默认字段分隔符:  单个或多个空格 、\tab 、 当\n不是记录分隔符的时候(默认分隔符被自定义),\n就代表字段分隔符

注意:单个或多个空格 、\tab 、 \n  这些字段分隔符同时出现时都起作用。


7.系统内建变

(1)记录变量

$0       整条记录

NR      记录个数         mumber   of  record(记录号---->默认记录分隔符为\n时,类似每行行号)   在主输入循环中执行

  awk  '{print  NR}'  a.txt

FNR    同时处理多个文本时显示行号

例题:

[root@bijz /]# cat 2.txt
acccca
acccca
acccaa
[root@bijz /]# cat 3.txt
hnah Hello World
nice too mEet you
how are yoOou hAn meimei
[root@bijz /]# awk '{print NF}' 2.txt 3.txt
1
1
1
3
4
5
[root@bijz /]# awk '{print NR}' 2.txt 3.txt
1
2
3
4
5
6
[root@bijz /]# awk '{print FNR}' 2.txt 3.txt
1
2
3
1
2
3

RS       输入记录分隔符 (在处理文本之前进行自定义,所以定义在BEGIN{}中

awk 'BEGIN{RS="o"}{print NR,$0}'  a.txt

ORS    输出记录分隔符

(2)字段变量

$1        第一个字段

$2        第二个字段

$3        第三个字段

NF       字段个数(注意区分:NR是记录个数)

FS        输入字段分隔符(默认单个或多个空格 、\tab 、或者不代表记录分隔符的\n )

自定义FS例题:

#awk  'BEGIN{FS=":"}{print $1,$3}'


OFS      输出字段分隔符  (在BEGIN{}中自定义 -- #awk  'BEGIN{}')

在输出字段分隔符中,逗号是默认的OFS输出字段分隔符,输出到屏幕上表现为空格

默认是把$1,$3之间的逗号输出到屏幕上是空格。自定义OFS后,$1,$3之间的逗号输出到屏幕时就是自己定义的连接符

例题:

方法一:自定义OFS

# awk 'BEGIN{FS=":";OFS="-"}{print $1,$3}' 1.txt
方法二:直接修改输出打印$1和$3之间的逗号

# awk 'BEGIN{FS=":"}{print $1"-"$3}' 1.txt


FILENAME     被处理的文件的名称

#awk  '{print  FILENAME}'  1.txt-->注意:因为是awk是一行一行进行处理,所以该命令执行会出现多行被处理文件的名称1.txt


8.格式化打印printf 

(format-expression  print)   format-expression:格式化表达式

c   ASCII字符

  字符串

  十进制整数

   浮点格式(实数)

x   无符号十六进制

#printf  “%-10s%-20s\n”  hello  world 

-10字符串共占用10个字符         -左对齐        %s定义字符串格式(接受后面文件的字符串变量)        \n换行       \t  tab键


例题:针对/etc/passwd

(1)输出 用户名和UID中间用:分割开,并把UID用()包括起来。

# awk   'BEGIN{FS=":";print"yonghu","UID";OFS=":"}{print $1,"("$3")"}'    /etc/passwd

(2)针对/etc/passwd把用户名和UID分开对齐排列

# awk 'BEGIN{FS=":";printf ("%-20s%-5s\n","yonghu","UID")}{printf ("%-20s%-5s\n",$1,$3)}'   /etc/passwd
yonghu              UID  
root                    0    
bin                      1    
daemon              2    
adm                    3    
lp                        4    
sync                    5    

9.手动指定FS的值:

第一种方法:

#awk  'BEGIN{FS=":|="}{print  $1}'   a.txt   

第二种方法:

#awk  -F :  '{print  $2}'  a.txt

#awk  -F =  '{print  $2}'  a.txt

#awk  -F  ':|='  '{print  $2}'  a.txt


# awk   -F"\t"   '{ print $2 }'  a.txt    ----分隔符为tab键

# awk   -F"\t+"   '{ print $2 }'  a.txt   ----分隔符为一个或多个tab键

# awk   -F"[':\t]"   '{ print $2 }'   a.txt     ----任何3个字符之一都可以被解释为字段分隔符

注意:-F后跟强引和弱引都可以

#awk  -F:  'OFS="aaa",ORS="bbb"{print  NR,FNR,NF,FILENAME}'  a.txt   b.txt

10.字段的引用和分离

(1)awk允许使用字段操作符$来指定字段。$后面可以跟着一个数字或者一个变量。

(2)$1表示第一个字段,$2表示第二个字段,$0表示整个输入记录。

(3)#awk   '{print  $1,$3}'   a.txt    ----->输出a.txt文件每行的第一个字段(第一列)和第二个字段(第二列)

(4)可以使用计算值为整数的表达式来表示一个字段

# echo A B C D | awk  'BEGIN { one = 1; two = 2} { print  $(one + two) }'
C


12.表达式:

(1)常量:能赋值给变量的

分成两种:字符串型和数字型
字符串型在表达式中必须用引号括起来
字符串中可以使用转义序列,常用的转义序列有:
\n 换行 \t 水平制表符

windows系统的换行 \n \r
linux系统的换行 \n


(2)变量---字符串
x=1
x是变量的名字 =是一个赋值操作符 1是一个数字常量
注意:变量区分大小写,所以x 和X(大写)表示不同的变量
变量名只能由数字字母下划线组成,而且不能以数字开头
变量使用不区分类型,使用前不必初始化
z = "Hello"
z = "Hello" "World"
z = $1
以上几种都是合法的

13.常用算术操作符:

+

-

*               ----shell中: #echo  $[5*8]      输出:40

/             -----除

%           ----取模(取余)    # echo   $[5%8]     ---->结果为5


x=1 给x赋值
y=x+1 计算x的值,使它加1,并将结果赋给变量y。
print y 打印y的值。
我们可以将这3个语句减少为两个:
x=1

print x+1


14.常用赋值操作符

++

- -

+=              sum+=$i   相当于sum=sum+$i

-=

*=

/=

%=

^=      ----->取幂

例题:

计算文件中空行的数目

# awk   '/^$/{x++}END{print x}'   2.txt

x当作字符串时初始代表空,当作数字时初始是0

15.关系操作符和布尔操作符

(1)关系操作符

<

>

<=

>=

= =              关系操作符= =和赋值操作符=是不同的    

(一个=是赋值,两个= =是判断等号两侧是否相等)

NF == 5

NF(每个输入记录的字段数)的值和5相比较,如果结果为真,那么就进行相应的处理,否则不进行处理。

!=

~     匹配    

使用匹配规则

/MA/ { print  $1 "," $6}

为了避免假警报,可以使用更精确的匹配

$5  ~  /MA/ {print  $1  ","  $6 }  ------->匹配第5列有MA的行

!~   不匹配

$5  !~  /MA/ {print  $1  ","  $6 }  ------->不匹配第5列有MA的行

(2)布尔操作符  (bool 逻辑操作符)

||  或

&&  与   

NF == 6 && NR > 1  --->(字段的数量必须等于6并且记录的编号必须大于1)

前面的命令如果执行错误,后面的命令就不再执行

!     非

注意:在awk中,真非0假0    shell中真0 假非0

16.向脚本传递参数

方式1:
# var=root
# awk  -F:  -v  a=$var  '$1==a {print}'   /etc/passwd

方式2:
[root@wing ~]# a=9
[root@wing ~]# awk   'BEGIN{print   '"$a"'  }'
9

17.条件、循环

(1)条件语句if

if ( expression ){
action1;
action1;
}
else{
action2       多条命令,换行后可以加分号,也可以不加
action2

}


注意;

如果操作是由多个语句组成,要用一个大括号将操作括起来

if ( expression ) {
statement1
statement2

}



例题

if ( x ) print x

如果x是零,则print语句将不执行。如果x是一个非零值,将打印x的值。

if  ( x ~ /[yY](es)?/ )  print x    ---> es一起,有一个或多个es



其他例子(有关成绩等级)

if  (avg >=65)

    grade = "pass"

else

    grade ="fail"



if (avg >=90)  grade ="A"

else if  (avg>=80)  grade="B"

else if  (avg>=70)  grade="C"

else if  (avg>=60)  grade="D"

else  grade="F"

解释:这种能够连续条件只有当一个条件表达式计算结果为真时才停止求值,这时将

跳过其他的条件。如果没有一个条件表达式的计算结果为真,将执行最后的else部分。



条件操作符

expr ?    action1 : action2

例如:

grade = (avg>=60) ?  "pass" : "fail"

判断avg是否大于等于60,如果成功,输出Pass给grade,如果失败,输出Fail给grade


#awk  -F:  '{print($3>$4? $3:$4)}'  /etc/passwd

注意小括号


(2)while 循环---死循环(先判断再做)

while (condition)

            action


例:

i =1

while (i<=4) {

          print  $i

           ++i

}


(3)do 循环
do ---先做再判断
action
while (condition)

例:

BEGIN {

    do{

        ++x

         print  x

       }  while (x<=4)

}

(4)for循环

for(变量初始化;变量变化范围-条件;增幅)

               动作


for (num=1;num<=9;num++)
print num
先执行循环体再执行num++

             

从第一个字段到最后一个字段
for ( i = 1; i <= NF; i++ )
print $i

从最后一个字段到第一个字段
for ( i = NF; i >= 1; i-- )
print $i


求阶乘 factorial
5!=5*4*3*2*1
number=8
fact = number
for (x = number - 1 ; x > 1; x--)
fact *= x
print fact


* * * * *

* * * * *

* * * * *
答案:
vim a.sh
BEGIN{
    for(i=1;i<=3;i++){
    for(j=1;j<=5;j++)
        printf("*")
    printf("\n")
    }
}
awk   -f  a.sh

for有多个循环体时加{   }

作业:

1.有一个文本:内容如下
姓名:wing
性别:male
电话:18623432212

姓名:jim
性别:male
电话:18223432123

姓名:hanmeimei
性别:female
电话:18123432212

要求用awk打印每个人的姓名和电话,格式如下:
姓名:wing 电话:18623432212
姓名:jim 电话:18223432123
姓名:hanmeimei 电话:18123432212


答案:# awk 'BEGIN{FS="\n";RS="\n\n"}{printf ("%-15s%-5s\n",$1,$3)}' a

2.打印当前目录下所有文件大小和大小总结:显示结果如下
文件名称 文件大小
a.txt 23
b.txt 23
总大小:


答案:# ll  | awk '{printf ("%-10s%-5s\n",$9,$5)};{total+=$5}END{print "总大小:",total}'

3.有文件name.txt内容如下:
# cat name.txt
tom 23 23 45 22 22
jim 23 23 45 22 22 28
xulong 23 23 45 22 22 82 23
yangsen 23 23 45 22 22 23 45 32 23

用awk打印每个人的平均成绩:格式如下
姓名 avg
tom 28
jim 30
xulong 50
yangsen 18

#awk -f src.txt name.txt
#cat src.txt
BEGIN{
print "姓名","平均成绩"
}
{
for(i=2;i<=NF;i++){
sum=sum+$i
}
avg=sum/(NF-1)
print $1,avg
sum=0
}

猜你喜欢

转载自blog.csdn.net/bijingzhao123/article/details/80113509