; GNU awk基础 | Linux运维部落

GNU awk基础

awk介绍

  • awk:Aho, Weinberger, Kernighan,报告生成器,格式化文本输出
  • 有多种版本:New awk(nawk),GNU awk( gawk)
  • gawk:模式扫描和处理语言
  • 基本用法:

awk [options] ‘program’ var=value file…

awk [options] -f programfile var=value file…

awk [options] ‘BEGIN{ action;… } pattern{ action;… } END{ action;… }’ file …

awk 程序通常由:BEGIN语句块、能够使用模式匹配的通用语句块 、END语句块,共3部分组成

program通常是被单引号或双引号中

  • 选项:

-F 指明输入时用到的字段分隔符

-v var=value: 自定义变量

 

awk不能修改文件,只做输出显示处理

 

[root@localhost ~]# which awk

/usr/bin/awk

[root@localhost ~]# ll /usr/bin/awk

lrwxrwxrwx. 1 root root 4 Dec 14 21:53 /usr/bin/awk -> gawk

 

awk语言

  • 基本格式:awk [options] ‘program’ file…
  • program:pattern{action statements;..}
  • pattern和action:

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

BEGIN,END

pattern决定了是针对那种类型的行进行处理。虽然默认把每一行都读进来,但是读进来的行要不要处理,可以定义pattern进行过滤,例如:如果满足pattern就执行动作,不满足就不符合条件,就可以直接跳到下一行开始。

action statements对数据进行处理,放在{}内指明。打印显示必要的内容

print, printf

 

print:简单的把必要的内容数据显示出来

printf:更加具体详细的定义显示的格式,例如添加控制符,打印的时候字段和字段之间有多宽、小数点有多少位

 

  • 分割符、域和记录

awk执行时,由分隔符分隔的字段(域)标记,分割成若干个列,每个列系统会自动分配变量$1,$2..$n对应的表示他们,用$1,$2..$n分别表示这一行的第几列,称为域标识。$0为所有域,注意:和shell中变量$符含义不同

文件的每一行称为记录默认回车换行分割记录

省略action,则默认执行 print $0 的操作打印一整行

$0为所有域整行的所有字段

 

在bash中$0 表示程序本身

 

 

printf也是一个内部命令,作用和echo相似,按照一定格式显示字符串

[root@localhost ~]# type printf

printf is a shell builtin

[root@localhost ~]# man printf

NAME

printf – format and print data 格式化和打印数据

 

记录不一定非得是一行才成为一条记录,例如:别的形式

[root@localhost ~]# vim file

a:bb;ccc:ddd;

例如该文件中,可以认为“:”分开的为字段,“;”分开的为记录(一行),不是按照回车换行为记录的分隔符,默认记录的分割符是回车换行,也可以是别的字符

 

 

 

awk工作原理

  • 第一步:执行BEGIN{action;… }语句块中的语句

 

  • 第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。

从命令的执行结果来的数据去读取第一行,然后去执行pattern中的action,看是否符合pattern定义,如果符合pattern定义就执行里面的action,不符合就不处理,读取下一行,知道文件处理完

 

  • 第三步:当读至输入流末尾时,执行END{action;…}语句块

 

  • BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个 可选的语句块,比如变量初始化、打印输出表格的表头等语句通常 可以写在BEGIN语句块中

 

  • END语句块在awk从输入流中读取完所有的行之后即被执行,比如 打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块

 

  • pattern语句块中的通用命令是最重要的部分,也是可选的。如果 没有提供pattern语句块,则默认执行{ print },即打印每一个读取 到的行,awk读取的每一行都会执行该语句块

 

awk

  • print格式: print item1, item2, … item1表示要打印的字符,可以是普通字符串,也可以是要打印的列
  • 要点:

(1) 逗号分隔符

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

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

  • 示例:

awk ‘{print “hello,awk”}’

awk –F: ‘{print}’ /etc/passwd

awk –F: ‘{print “wang”}’ /etc/passwd

awk –F: ‘{print $1}’ /etc/passwd awk –F: ‘{print $0}’ /etc/passwd

awk –F: ‘{print $1”\t”$3}’ /etc/passwd tail –3 /etc/fstab |awk ‘{print $2,$4}’

 

例子:

如果pattern忽略不写,就会处理所有行

每读一行显示一行,读进来一看,pattern未定义,符合条件,符合条件就打印

[root@localhost /app]# awk ‘{print “hello”}’ /etc/issue

hello

hello

 

从标准输入读取输入进行打印

[root@localhost /app]# awk ‘{print “hello”}’

a

hello

b

hello

 

awk可以读取标准输入

[root@localhost /app]# cat /etc/issue | awk ‘{print “hello”}’

hello

hello

hello

管道把前一个命令的标准输出作为后一个命令的标准输入

 

[root@localhost /app]# awk ‘{print “hello\nclass27″}’ /etc/centos-release

hello

class27

 

做数字运算,只要是字符串,就需要加引号引起来,数字不需要加引号

[root@localhost /app]# awk ‘{print 2*3}’ /etc/centos-release

6

[root@localhost /app]# awk ‘{print 2^3}’ /etc/centos-release

8

[root@localhost /app]# awk ‘{print 2/3}’ /etc/centos-release

0.666667

 

希望取出特定的字段,awk默认的分隔符是空格

[root@localhost /app]# awk -F “:” ‘{print $1,$3,$7}’ passwd

 

取分区的利用率

[root@localhost /app]# df | grep /dev/sd | awk ‘{print $5}’

8%

1%

4%

[root@localhost /app]# df | grep /dev/sd | awk ‘{print $1,$5}’

/dev/sda2 8%

/dev/sda3 1%

/dev/sda1 4%

 

{print $1,$5},$1 和 $5 之间使用“,”,输出时字段的分割符为空格,也可以进行指定,例如:

[root@localhost /app]# df | grep /dev/sd | awk ‘{print $1″——“$5}’

/dev/sda2——8%

/dev/sda3——1%

/dev/sda1——4%

 

[root@localhost /app]# df | grep /dev/sd | awk ‘{print $1”\t“$5}’

/dev/sda2 8%

/dev/sda3 1%

/dev/sda1 4%

[root@localhost /app]# df | grep /dev/sd | awk ‘{print $1”\n“$5}’

/dev/sda2

8%

/dev/sda3

1%

/dev/sda1

4%

$0打印整行内容

默认不写也是打印整行内容

[root@localhost ~]# df | grep ‘dev/sd’ | awk ‘{ print }’

/dev/sda2 52403200 16332416 36070784 32% /

/dev/sda5 20961280 51048 20910232 1% /app

/dev/sda1 1038336 227464 810872 22% /boot

 

[root@localhost ~]# df | grep ‘dev/sd’ | awk ‘{ print $0 }’

/dev/sda2 52403200 16332416 36070784 32% /

/dev/sda5 20961280 51048 20910232 1% /app

/dev/sda1 1038336 227464 810872 22% /boot

 

 

 

awk变量

  • 变量:内置和自定义变量
  • FS:输入字段分隔符,默认为空白字符

awk -vFS=’:’ ‘{print $1,FS,$3}’ /etc/passwd

awk –F: ‘{print $1,$3,$7}’ /etc/passwd

 

awk -vFS=’:’等价于 awk -F ‘:’

 

FS:field,称为域、字段、列column、属性

行,称为记录,record

 

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

awk -v FS=‘:’ -v OFS=‘:’ ‘{print $1,$3,$7}’ /etc/passwd

 

  • RS:输入记录分隔符,指定输入时的换行符

awk -v RS=’ ‘ ‘{print }’ /etc/passwd

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

awk -v RS=’ ‘ -v ORS=’###’‘{print }’ /etc/passwd

  • NF:字段数量

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

awk -F: ‘{print $(NF-1)}’ /etc/passwd

  • NR:记录号

awk ‘{print NR}’ /etc/fstab ; awk END'{print NR}’ /etc/fstab

 

-v表示给变量赋值,FS是awk自带的变量,字段的分隔符,指定文件输入的分隔符是什么

[root@localhost /app]# awk -F ‘:’ ‘{print $1,$3}’ passwd

[root@localhost /app]# awk -v FS=’:’‘{print $1,$3}’ passwd

 

变量的好处是可以在awk中输出时使用

[root@localhost /app]# awk -v FS=’:’ ‘{print $1,FS,$3}’ passwd

root : 0

bin : 1

 

awk还可以使用bash变量,例如调用bash中的变量

[root@localhost /app]# sep=”:”;awk -v FS=”$sep” ‘{print $1,FS,$3}’ passwd

root : 0

bin : 1

-F只能在外面使用bash中的变量,但是里面就无法使用了

[root@localhost ~]# sep=”:”;awk -F “$sep” ‘{print $1,”:”$3}’ passwd

root :0

bin :1

 

 

 

输出分隔符

[root@localhost /app]# awk -v FS=’:’-v OFS=’+’‘{print $1,$3}’ passwd

root+0

bin+1

输入分割符决定字段之间怎么分割进行处理

输出分隔符决定字段之间怎么输出进行显示

 

把一个文件读进来怎么知道怎样算是一条记录?默认回车换行是一条记录

例如:认为一条记录的分割符为‘;’,字段的分隔符默认为空白符

[root@localhost /app]# cat file

aa bbcc;ee

ffoo;xx

yyzz

 

[root@localhost /app]# awk -v RS=”;”‘{print $2}’ file

bb

ff

yy

 

[root@localhost /app]# cat file

a

b

caa

bb

ccaaa

bb

cccaaa

以空格作为行的分隔符

[root@localhost /app]# awk -v RS=” ” ‘{ print $1,$2}’ file

a b

aa bb

aaa bb

aaa

以空格作为行的分隔符,所以abc算是一条记录,默认字段的分割符为空白符,回车换行也是空白符,所以a是$1,b是$2,c是$3,所以第一行为a b

所以,记录分别是:

a b c

aa bb cc

aaa bb ccc

aaa

输出的时候一条一条的记录默认是换行分割出来的,输出的时候,记录和记录之间到的默认分割符是回车换行

指定输出的分隔符

[root@localhost ~]# cat f2.txt

a b

aa bb

aaa bb

aaa

指定输出记录的分隔符

[root@localhost ~]# awk -v RS=” ” -v ORS=”—“‘{print $1,$2}’ f2.txt

a —b aa—bb aaa—bb aaa—

 

字段数量NF

显示每个行有多少个字段

[root@localhost ~]# awk -F: ‘{print NF}’ /etc/passwd

7

 

输出最后一个字段

[root@localhost ~]# awk -F: ‘{print $NF}’ /etc/passwd

/bin/bash

 

输出倒数第二个字段

[root@localhost ~]# awk -F: ‘{print $(NF-1)}’ /etc/passwd

/root

 

取出远程连接IP

[root@localhost ~]# ss -nt | awk ‘{print $NF}’ | awk -F: ‘{print $1}’

Address

172.18.101.66

 

取出分区利用率

[root@localhost ~]# df | grep ‘/dev/sd’ | awk ‘{print $(NF-1)}’|awk -F% ‘{print $1}’

32

1

22

取http访问日志

[root@localhost /app]# awk ‘{print $1}’ /var/log/httpd/access_log

172.18.101.66

 

NR:记录号,每条记录的编号

[root@localhost /app]# awk ‘{print NR,$0}’ /etc/passwd

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

 

空行也算行号

[root@localhost /app]# awk ‘{print NR,$0}’ /etc/fstab

1

2 #

3 # /etc/fstab

 

同时处理多个文件

[root@localhost /app]# awk ‘{print NR,$0}’ /etc/fstab /etc/issue

在第一个文件输出完之后接着输出第二个文件的内容

 

同时处理多个文件,每个文件独立编号

[root@localhost /app]# awk ‘{print FNR,$0}’ /etc/fstab /etc/issue

1

2 #

3 # /etc/fstab

1 \S

2 Kernel \r on an \m

3

 

显示文件名

[root@localhost /app]# awk ‘{print FNR,FILENAME,$0}’ /etc/fstab /etc/issue

1 /etc/fstab

2 /etc/fstab #

3 /etc/fstab # /etc/fstab

1 /etc/issue \S

2 /etc/issue Kernel \r on an \m

3 /etc/issue

 

awk

  • FNR:各文件分别计数,记录号

awk ‘{print FNR}’ /etc/fstab /etc/inittab

  • FILENAME:当前文件名

awk ‘{print FILENAME}’ /etc/fstab

  • ARGC:命令行参数的个数

awk ‘{print ARGC}’ /etc/fstab /etc/inittab

awk ‘BEGIN {print ARGC}’ /etc/fstab /etc/inittab

 

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

awk ‘BEGIN {print ARGV[0]}’ /etc/fstab /etc/inittab

awk ‘BEGIN {print ARGV[1]}’ /etc/fstab /etc/inittab

 

命令行参数的个数

[root@localhost ~]# awk ‘{print ARGC}’ /etc/fstab /etc/issue

3

[root@localhost /app]# awk ‘{print ARGV[0]}’ /etc/fstab /etc/issue

awk

[root@localhost /app]# awk ‘{print ARGV[1]}’ /etc/fstab /etc/issue

/etc/fstab

[root@localhost /app]# awk ‘{print ARGV[2]}’ /etc/fstab /etc/issue

/etc/issue

三个参数从0开始编,认为awk也是参数之一

 

 

awk变量

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

(1) -v var=value

(2) 在program中直接定义

  • 示例:

awk -v test=’hello gawk’ ‘{print test}’ /etc/fstab

awk -v test=’hello gawk’ ‘BEGIN{print test}’

awk ‘BEGIN{test=”hello,gawk”;print test}’

awk –F:‘{sex=“male”;print $1,sex,age;age=18}’ /etc/passwd

cat awkscript {print script,$1,$2} awk -F: -f awkscript script=“awk” /etc/passwd

 

自定义变量

#awk -v sep=”:”-F: ‘{print $1sep$3}’ /etc/passwd

root:0

 

分别进行定义

# awk -v uid=”uid” -F: ‘{user=”username”;print user”:”$1,uid”:”$3}’ /etc/passwd

username:root uid:0

 

#awk -v user=”username”-v uid=”uid”-F: ‘{print user”:”$1,uid”:”$3}’ /etc/passwd

username:root uid:0

 

在program中直接定义

# awk -F: ‘{user=”username”;uid=”uid”; print user”:”$1,uid”:”$3}’ /etc/passwd

username:root uid:0

定义在awk程序里面不能使用bash中的变量,在外部定义可以使用bash中的变量

 

# u=”user”;awk -F: -v user=”$u”‘{uid=”uid”; print user”:”$1,uid”:”$3}’ /etc/passwd

user:root uid:0

 

 

先使用后定义会现第一行不生效的问题

# awk -F: ‘{print user”:”$1,uid”:”$3;user=”user”;uid=”userid”}’ /etc/passwd

:root :0

user:bin userid:1

原因:第一行读取进来进行处理的时候,user和uid还是未定义的状态,但是到第二行的时候,就已经是定义了的状态了。这一行定义的变量将会在下一行起作用。为避免出现问题,建议先声明后使用

 

 

把awk的指定放入文件中

[root@localhost ~]# cat awk.script

{user=”username”;uid=”userid”;print user”:”$1,uid”:”$3}

 

[root@localhost ~]# awk -F: -f awk.script/etc/passwd

username:root userid:0

本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:/90685

发表评论

电子邮件地址不会被公开。 必填项已用*标注

联系我们

400-080-6560

在线咨询:点击这里给我发消息

邮件:1660809109@qq.com

工作时间:周一至周五,9:30-18:30,节假日同时也值班

友情链接:万达主管QQ  万达开户  万达娱乐注册  万达娱乐  万达直属  guoqibee.com  万达直属QQ  万达注册  万达娱乐主管QQ  测试