awk

awk [-F 分隔符] '{command}' filename
awk  -F    :    '{print $1}'  1.txt

$0则表示所有域,$1表示第一个域,$n表示第n个域。

功能

使用变量

VAR1="~~~!"
echo hello, world|awk -v awk_var1=$VAR1 '{ print $1, "shell", $2, awk_var1 }'

hello, shell world ~~~!

将结果赋值给多个多个变

要利用的eval命令,eval命令可以将它的参数当作shell命令执行

line=172.20.7.13,82.157.52.185,beijing-7,LINE-BJ-T2-005,LINE-BJ-T2-005,BJ-T2-BJ-BJ-BJ-A-T-005
eval `echo $line | awk -F , '{printf "ip=%s;pubIP=%s;Zone=%s;InsName=%s;hostname=%s;hostname2=%s", $1, $2, $3, $4, $5, $6}'`

echo $ip, $pubIP, $Zone, $InsName, $hostname, $hostname2
172.20.7.13, 82.157.52.185, beijing-7, LINE-BJ-T2-005, LINE-BJ-T2-005, BJ-T2-BJ-BJ-BJ-A-T-005

不要空白行

awk -F '|' 'NF>1{print $3}'    # NF>1 表示分隔时,分割的字段数NF大于 1时,awk才处理打印此行,空行自然不会去处理了。

打印双引号

awk '{print "\""}'        #放大:awk '{print "  \"  "}'
使用“”双引号把一个双引号括起来,然后用转义字符\对双引号进行转义,输出双引号。

打印单引号

awk '{print "'\''"}'       # 放大: awk '{print  "  '  \  '  '   " }'
使用一个双引号"",然后在双引号里面加入两个单引号'',接着在两个单引号里面加入一个转义的单引号\',输出单引号。

打印制表符

awk '{print $1"\t"$2}'

BEGIN/END作用

# 初始化变量,统计行数
awk 'BEGIN { count = 0 } { count++ } END { print "Total lines:", count }' file.txt

# 设置字段分隔符,使用 FS 变量来设置字段分隔符
awk 'BEGIN { FS = "," } { print $1 }' data.csv

# 打印表头
awk 'BEGIN { print "Name\tAge\tGender"; } { print $1, $2, $3; }' file.txt

# 设置输出格式
awk 'BEGIN { printf "%-10s %-10s %-10s\n", "Name", "Age", "Gender"; } { printf "%-10s %-10s %-10s\n", $1, $2, $3; }' file.txt

多分隔符

awk -F '[:/=, ]+' '{printf "%s", $1}'
# -F '[:/=, ]+' 表示指定分隔符可以是:或者 (空格) 这里指定多个分隔符
# [ ] 表示一个字符的集合,+则是一个正则表达式,表示+前面的字符(:或者空格)重复1次或者一次以上

awk -F '  +' '{print $1";"$2}'
# -F '  +' 表示两个或以上的空格字符。

使用内置变量作为输出分隔符

awk -v OFS='\t'

内置变量(预定义变量)

说明:[A][N][P][G]表示第一个支持变量的工具,[A]=awk、[N]=nawk、[P]=POSIXawk、[G]=gawk
$n 当前记录的第n个字段,比如n为1表示第一个字段,n为2表示第二个字段。
$0 这个变量包含执行过程中当前行的文本内容。
[N] ARGC 命令行参数的数目。
[G] ARGIND 命令行中当前文件的位置(从0开始算)。
[N] ARGV 包含命令行参数的数组。
[G] CONVFMT 数字转换格式(默认值为%.6g)。
[P] ENVIRON 环境变量关联数组。
[N] ERRNO 最后一个系统错误的描述。
[G] FIELDWIDTHS 字段宽度列表(用空格键分隔)。
[A] FILENAME 当前输入文件的名。
[P] FNR 同NR,但相对于当前文件。
[A] FS 字段分隔符(默认是任何空格)。
[G] IGNORECASE 如果为真,则进行忽略大小写的匹配。
[A] NF 表示字段数,在执行过程中对应于当前的字段数。
[A] NR 表示记录数,在执行过程中对应于当前的行号。
[A] OFMT 数字的输出格式(默认值是%.6g)。
[A] OFS 输出字段分隔符(默认值是一个空格)。
[A] ORS 输出记录分隔符(默认值是一个换行符)。
[A] RS 记录分隔符(默认是一个换行符)。
[N] RSTART 由match函数所匹配的字符串的第一个位置。
[N] RLENGTH 由match函数所匹配的字符串的长度。
[N] SUBSEP 数组下标分隔符(默认值是34)。

去除重复行

  重复的数据总是让人各种不爽,占用空间、看起来费劲等等,今天就介绍一个通过awk去除文件中重复数据的办法,awk默认是一行行来处理数据的,那我们就重点说说如何通过awk去除文件中的重复行。

  首先准备一个文本文件,随便写个文件,包含重复行数据的即可,或者你可以参考我这里的文件:

CodingAnts@ubuntu:~/awk$ cat dup
hello world
awk
coding ants
hello world
awk
hello world
awk
coding ants
coding ants

  共有9行,后面6行都是重复的前面的几行,最终的效果应该是只显示上面重点显示的那几行,先来看看效果:

CodingAnts@ubuntu:~/awk$ awk '!a[$0]++' dup
hello world
awk
coding ants

  在《awk程序指令模型》中介绍了awk的程序指令由模式和操作组成,即Pattern { Action }的形式,如果省略Action,则默认执行 print $0 的操作。

  实现去除重复功能的就是这里的Pattern:

!a[$0]++

  在awk中,对于未初始化的数组变量,在进行数值运算的时候,会赋予初值0,因此a[$0]=0,++运算符的特性是先取值,后加1,因此Pattern等价于

!0

  而0为假,!为取反,因此整个Pattern最后的结果为1,相当于if(1),Pattern匹配成功,输出当前记录,对于dup文件,前3条记录的处理方式都是如此。

  当读取第4行数据“hello world”的时候,a[$0]=1,取反后的结果为0,即Pattern为0,Pattern匹配失败,因此不输出这条记录,后续的数据以此类推,最终成功实现去除文件中的重复行。

指令模型

2012-03-19 By Coding Ants

  一个典型的awk 程序指令是由模式(Pattern)和大括号括起来的操作(Action)组合而成的,具体格式如下:

Pattern { Action }

  对于awk 读取的每条记录,如果一个记录与指定模式(Pattern)相匹配,或包含与该模式匹配的字段,那么执行相应的操作(Action)。

  模式和操作可以任意省略其中的一个,如果省略模式,则操作会被应用到每条输入记录;如果省略操作,则默认操作为将匹配的记录打印到标准输出上。假设有一个名为 visitor 的文本文件,记录了某段时间访问Coding Ants的人,具体如下,中间用tab进行分割。

guangdong    121.8.171.*    15:18:23    www.google.com.hk
guangdong    183.32.97.*    15:11:23    www.google.com
tianjing    111.166.108.*    15:10:22    www.baidu.com
guangdong    113.65.141.*    14:35:27    www.baidu.com
shanghai    123.126.50.*    14:18:23    www.google.com.hk
shanghai    117.136.0.*    14:17:23    www.google.com

  visitor文件共有6行,每行由tab分割为4个部分,对awk 来说,这就是6条记录,每条记录包含4个字段!如果我们想查看来自广东的访问者,则可以执行下面的命令:

CodingAnts@ubuntu:~/awk$ cat visitor | awk '/guangdong/ {print $0}'
guangdong    121.8.171.*    15:18:23    www.google.com.hk
guangdong    183.32.97.*    15:11:23    www.google.com
guangdong    113.65.141.*    14:35:27    www.baidu.com

  上面蓝色部分的/guangdong/即为模式(Pattern),红色部分的print $0 为操作(Action)。上面的awk指令可以这样理解:awk读取visitor中的每条输入作为记录,然后将模式与记录进行匹配(查找记录中是否包含 guangdong 这个词),如果匹配,则执行操作(打印整条记录到标准输出)。

  接下来,我们分别省略模式和操作,看看输出的结果有什么差异。

CodingAnts@ubuntu:~/awk$ cat visitor | awk '/guangdong/'
guangdong    121.8.171.*    15:18:23    www.google.com.hk
guangdong    183.32.97.*    15:11:23    www.google.com
guangdong    113.65.141.*    14:35:27    www.baidu.com

  上面是省略操作后的输出,可以看出默认的操作就是 print $0,也就是打印整条记录!

CodingAnts@ubuntu:~/awk$ cat visitor | awk '{print $1,$4}'
guangdong www.google.com.hk
guangdong www.google.com
tianjing www.baidu.com
guangdong www.baidu.com
shanghai www.google.com.hk
shanghai www.google.com

  省略模式后,可以看出awk对于每条记录都执行了对应的操作(打印第一个和第四个字段)!

  总结下就是:模式(Pattern)用于筛选记录,操作(Action)用于处理字段!