linux文本处理工具三剑客之awk

        linux文本处理工具三剑客:grep、sed和awk。其中grep是一种文本过滤工具,sed是文本行编辑器,而awk是一种报表生成器,就是对文件进行格式化处理的,治理的格式化不是文件系统的格式化,而是对文件内容进行各种排版,进而格式化显示。

awk运行方式有三种:

(1)awk命令行

   #awk

(2)awk 程序文件:将所有的awk命令插入一个单独文件,然后调用

   #awk –f  文件路径

(3)awk脚本

 awk 基本格式:awk [options] 'program' file…

• program:编程语言

• pattern和action:

• pattern部分决定动作语句何时触发及触发事件 BEGIN,END

BEGIN:在文件格式化操作开始之前事先执行的一次操作;通常用于输出表头或者作出一个预处理操作

END:在文件格式化操作开始之后,命令退出之前执行的一次操作;通常用于输出表尾或者作出清理操作

• action statements:动作语句,可以是多个语句组成,各语句之间使用分号分割;如{print,printf}

options:

-F[]   输入字段分隔符;

-v     变量名 =值:变量赋值

-f      路径

        awk在处理文本时也是 一次读取一行文本,然后根据输入分隔符(默认空格)进行切片,切成n个片段,然后将每一片都赋予awk内部的一个变量当中来保存,这些变量名为$1,$2等到最后一个,awk可以对这些片段单独进行处理,显示某一段,并进行处理,如计数、运算等

1.awk的输出命令之一:print

   print格式: print item1, item2, ...

   要点:

  (1) 逗号分隔符;输出分隔符默认为空白字符

  (2) 输出的各item可以字符串,也可以是数值;当前记录的字段、变量或awk的表达式

  (3) 如省略item,相当于print $0

2.awk的输出命令之二:printf格式化输出

  格式化输出:printf “FORMAT”, item1, item2, ...

  (1) 必须指定FORMAT

  (2) 不会自动换行,需要显式给出换行控制符,\n

  (3) FORMAT中需要分别为后面每个item指定格式符 

• 格式符:与item一一对应 

%c: 显示字符的ASCII码

%d, %i: 显示十进制整数 

%e, %E:显示科学计数法数值

%f:显示为浮点数 

%g, %G:以科学计数法或浮点形式显示数值 

%s:显示字符串

%u:无符号整数

%%: 显示%自身

[root@centos6 ~]#awk -F: '{printf "username:%-15s  uid:%-5d\n",$1,$3}' /etc/passwd 
username:root uid:0
username:bin uid:1
username:Root uid:0
username:daemon uid:2
username:adm uid:3
username:GAMES uid:0

• 修饰符:

#[.#]:第一个数字控制显示的宽度;第二个#表示小数点后精度,

%3.1f :

[root@centos6 ~]#awk -F: 'BEGIN{printf "%.2d %1.2f\n",1.73333,3.1111}' 

01 3.11

左对齐(默认右对齐) 

%-15s

经典例子:查看分区利用率大于10%的分区,并打印(先把%去掉)

[root@centos6 ~]#df |awk -v FS="%" '$0 ~ "/dev/sd" {print $1}'|awk '$NF>=10 {printf "devicename:%-15s used:%s%%\n",$1,$5}' 

devicename:/dev/sda2       used:85% 

devicename:/dev/sda3       used:63% 

devicename:/dev/sda1       used:20%

printf和print区别:

awk中同时提供了print和printf两种打印输出的函数。

其中print函数的参数可以是变量、数值或者字符串。字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。

printf函数,其用法和c语言中printf基本相似,可以格式化字符串,输出复杂时,printf更加好用,代码更易懂。

3.变量

变量:内置和自定义变量

3.1、内置变量

FS:输入字段分隔符,默认为空白字符 (等同于-F:)

[root@centos6 ~]#awk -v FS=':' '{print $1,$3}' /etc/passwd

 root 0 

bin 1 

Root daemon 2 

adm 3 

GAMES lp 4

[root@centos6 ~]#awk -F: '{print $1,$3}' /etc/passwd 

root 0

 bin 1 

Root daemon 2 

adm 3 

GAMES lp 4 

OFS:输出字段分隔符,默认为空白字符

[root@centos6 ~]#awk -v FS=':' -v OFS='#' '{print $1,$3}' /etc/passwd 

root#0 

bin#1 

Root# 

daemon#2 

adm#3 

RS:输入记录分隔符,指定输入时的换行符,原换行符仍有效

[root@centos6 ~]#cat f 

aaa fferrb fggrefd.fgrgf bbbbb mmsmsmfm 

 fgbfk.f fvc.werr ewregtrb.ew  wereg

[root@centos6 ~]#awk -v FS='.' -v RS=" " '{print $1}' f 

aaa fferrb fggrefd mmsmsmfm

fgbfk ewregtrb

wereg 

ORS:输出记录分隔符,输出时用指定符号代替换行符

[root@centos6 ~]#awk -v FS='.' -v RS=" " -v ORS="#" '{print $1}' f 
aaa#fferrb#fggrefd#mmsmsmfm##fgbfk#ewregtrb##wereg #

NF:字段数量 awk -F: ‘{print NF}’ /etc/fstab,引用内置变量不用$

[root@centos6 ~]#awk -F" " '{print NF}' /etc/fstab 

0 

1

 2 

10

 1 

9 

12

 1

NR:行号

[root@centos6 ~]#awk '{print NR,$0}' /etc/fstab 

1 

2 #

 3 # /etc/fstab 

4 # Created by anaconda on Tue Jul 10 20:16:55 2018 

5 # 

6 # Accessible filesystems, by reference, are maintained under '/dev/disk' 

7 # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info 

8 # 

9 UUID=69175cc3-0636-46ac-9190-84a4bfa546ed /                       ext4    defaults

FNR:各文件分别计数,行号

[root@centos6 ~]#awk '{print FNR}' /etc/fstab /etc/inittab 

1 

2

 3 

4 

5 

6 

1

2 

3 

4 

5 

FILENAME:当前文件名

awk '{print FILENAME}’  /etc/fstab

ARGC:命令行参数的个数

[root@centos6 ~]#awk '{print ARGC}' /etc/fstab  /etc/shadow

 3 

3

 3

 3 

3

注意:awk 也是一个参数

ARGV:数组,保存的是命令行所给定的各参数

[root@centos6 ~]#awk 'BEGIN {print ARGV[0]}'  /etc/fstab /etc/inittab 

awk

打印命令行的最后一个参数

[root@centos6 ~]#awk 'BEGIN {print ARGV[ARGC-1]}'  /etc/fstab /etc/inittab /etc/haha hi hello 

hello 

3.2、自定义变量

自定义变量(区分字符大小写)

(1) -v var=value

[root@centos6 ~]#awk -v a="i miss you" 'BEGIN{print a}' 

i miss you 

(2) 在program中直接定义

[root@centos6 ~]#awk 'BEGIN{a="hi";print a}'

 hi

[root@centos6 ~]#awk '{sex="male";print sex,age;age=20}' /etc/fstab male 

/age=20在变量后边定义时,第一次age没值则为假不输出,后面会输出 male 20 male 20 male 20 male 20

对变量进行多次赋值时,注意b="$a",不能用单引号,它会完全转义。

[root@centos6 ~]#a="i love you";awk -v b="$a" '{c=b;print c}' /etc/fstab 

i love you                                                                   

 i love you

 i love you

 i love you 

注意:在内部定义变量=字符串时,字符串必须加引号,不然会被当成变量报错,但是变量=数字时,不用加引号

4.操作符

比较常用的几个:

算术表达式

[root@centos6 ~]#awk 'BEGIN{print 2^5}' 

32 

[root@centos6 ~]#awk 'BEGIN{print 15%4}' 

3

 [root@centos6 ~]#awk 'BEGIN{n=2;print n+=2 }' 

4 

模式匹配操作符:

~:左边是否和右边匹配包含

!~:是否不匹配

[root@centos6 ~]#awk '$0 ~ "^root"{print $0}' /etc/passwd 

root:x:0:0:root:/root:/bin/bash

 [root@centos6 ~]#awk -F: '$3 == 0{print $0}' /etc/passwd                     

root:x:0:0:root:/root:/bin/bash 

条件表达式(三目表达式):

selector?if-true-expression:if-false-expression

[root@centos6 ~]#awk -F: '{$3>=1000?usertype="com user":usertype="sys user";printf "username:%-15s usertype:%s\n",$1,usertype}' /etc/passwd 

username:root                    usertype:sys 

user username:bin              usertype:sys 

user username:Root           usertype:sys 

user username:daemon      usertype:sys user 

username:adm                    usertype:sys user 

关系表达式 为非0时,即为真,才处理 为0或为空时,不处理 !0=1  !Num=0  (Num为任意非0的值)

[root@centos6 ~]#awk 'BEGIN{print i++;print i}' 

0 

1

 [root@centos6 ~]#awk 'BEGIN{print ++i;print i}' 

1 

1

行范围(不能用行号)

[root@centos6 ~]#cat /boot/grub/grub.conf |awk '/default/,/hidden/' 

default=0 

timeout=5 

splashimage=(hd0,0)/grub/splash.xpm.gz 

hiddenmenu

[root@centos6 ~]#cat /boot/grub/grub.conf |awk 'NR>=2&&NR<=7' 

# 

# Note that you do not have to rerun grub after making changes to this file 

# NOTICE:  You have a /boot partition.  This means that

 #          all kernel and initrd paths are relative to /boot/, eg.

打印奇数行

[root@centos6 ~]#seq 10|awk 'i=!i' 
1 3 5 7 9

打印偶数行

[root@centos6 ~]#seq 10|awk '!(i=!i)' 

2 4 6 8 10 

5.常用动作:

(1)变量赋值

(2)控制语句

if-else

此语句使用场景:对awk取得的整行或某个字段做条件判断

计算男生平均成绩,女生平均成绩,总平均成绩,

要求输出结果

姓名     分数      性别

mage     100     male

lilin          90      female

yunzhen  85     female

xiaoxiao   55    male

男生平均成绩:xx

女生平均成绩: xx

总平均成绩:   xx

[root@centos6 ~]#awk 'BEGIN{printf "%-13s%-5s%-6s\n","姓名","分数","性别"} {printf "%-15s%-6s%-6s\n",$1,$2,$3;if($NF=="male"){count++;sum+=$2}else{count1++;sum1+=$2}sum3+=$2} END {printf "男生平均成绩:%.2f\n",sum/count;printf "女生平均成绩:%.2f\n",sum1/count1;printf "总平均成绩:%.2f\n",sum3/NR}' score.txt 姓名           分数   性别    

mage           100   male  l

ilin          90    female 

yunzhen        85    female 

xiaoxiao       55    male  

男生平均成绩:77.50 

女生平均成绩:87.50 

总平均成绩:82.50 

while循环

语法:while(condition){statement;...}

           条件“真”,进入循环;条件“假”,退出循环

           此语句使用场景:对一行内的多个字段逐一类似处理时使用;对数组中的各元素逐一处理时使用

[root@centos6 ~]#awk 'BEGIN{i=1;while(i<=1000000){sum+=i;i++};print sum}' 

500000500000

for循环

特殊用法:能够遍历数组中的元素

[root@centos6 ~]#awk 'BEGIN{for(i=1;i<=1000000;i++){sum+=i};print sum}' 

500000500000 

break和continue

next: 提前结束对本行处理而直接进入下一行处理(awk自身循环)

计算1-100偶数之和

[root@centos6 bin]#awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==1)continue;sum+=i};print sum}' 

2550

计算1-100奇数之和

root@centos6 bin]#awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i};print sum}' 

2500

仅显示uid为偶数的用户名和其uid

[root@centos6 bin]#awk -F: '{if($3%2!=0)next;print $1,$3}' /etc/passwd 

root 0

 daemon 2 

lp 4 

shutdown 6 

6.awk数组

关联数组:array[index-expression]

index-expression:

      (1)可以使用任意字符串;字符串要使用双引号括起来

      (2)如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”

若要遍历数组中的每个元素,要使用for循环

• for(var in array) {for-body}

• 注意:var会遍历array的每个索引

[root@centos6 bin]#awk -F: '{line[$7]++}END{for (i in line) {print i,line[i]}}' /etc/passwd 

/sbin/shutdown 1 

/bin/bash 4 

/sbin/nologin 28 

/sbin/halt 1 

/bin/sync 1

7.awk函数

数值处理:

rand():返回0和1之间一个随机数,要想随机生成任意一个数,则前面要加上srand()

[root@centos6 ~]#awk 'BEGIN{srand();print int(rand()*100)}' 

85 

字符串处理:

length([s]):返回指定字符串的长度(字符串里面有空格则包含)

[root@centos6 ~]#awk 'BEGIN{print length("i miss you")}' 

10 

sub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并将第一个匹配的内容替换为s

举例:

[root@centos6 ~]#echo "2018:08:30 08:59:05"|awk 'sub(/:/,"-",$1)' 

2018-08:30 08:59:05 

gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容

举例:

提取出字符串Yd$C@M05MB%9&Bdh7dq+YVixp3vpw中的所有数字

[root@centos6 ~]#echo 'Yd$C@M05MB%9&Bdh7dq+YVixp3vp'|awk 'gsub(/[^[:digit:]]/," ",$0)'

注意:这里只能用 单引号引住字符串    

split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组中,第一个索引值为1,第二个索引值为2....

举例:

[root@centos6 ~]#netstat -tan|awk '/^tcp\>/&&!($5 ~ "*"){split ($5,ip,":");count[ip[1]]++}END{for(i in count){print i,count[i]}}' 

172.18.250.74 1

8.awk中调用shell命令

system命令

• 空格是awk中的字符串连接符,如果system中需要使用awk中的变量可以使用空格分隔,或者说除了 awk的变量外其他一律用""引用起来。

[root@centos6 ~]#awk 'BEGIN{score=100;system("name=ms;echo $name score is "score )}' 

ms score is 100 

9.awk脚本

将awk程序写成脚本,直接调用或执行

向awk脚本传递参数

• 格式: awkfile var=value var2=value2... Inputfile

• 注意:在BEGIN过程中不可用。直到首行输入完成以后,变量才可用。可以通 过-v 参数,让awk在执行BEGIN之前得到变量的值。命令行中每一个指定的变 量都需要一个-v参数

[root@centos6 ~]#cat a.awk #!/bin/awk -f {if($3>=min&&$3<=max)print $1,$3}

[root@centos6 ~]#chmod +x a.awk 

[root@centos6 ~]#./a.awk -F: min=100 max=200 /etc/passwd 

usbmuxd 113 

avahi-autoipd 170 

abrt 173 

猜你喜欢

转载自www.cnblogs.com/f-h-j-11-7/p/9559314.html