Linux三剑客之一awk

1. 使用方法

// 命令格式
awk [options] 'pattern{action}' filenames
// 脚本格式
awk -f script_file filenames

1.1 命令格式

pattern表示 AWK 在数据中查找的内容,可以用正则表达式来进行匹配,用/斜杠括起来。
action是在找到匹配内容后执行的一系列命令。{}不需要在程序中始终出现,但它们用于根据特定的模式对指令进行分组。

1.2 行处理方式

awk默认是以行为单位处理文本的,对filenames每一行都执行{}中的语句。
记录:默认为文本中的每一行
字段:默认每个记录中由空格或TAB分隔的字符串
$0表示一条记录,即文本中的一行
$1表示记录中的第一个字段

下面通过解释一个简单的命令,来了解以下工作原理:

➜  ~ awk '{print $0}' /etc/passwd              
root:x:0:0::/root:/bin/bash
nobody:x:65534:65534:Nobody:/:/sbin/nologin
dbus:x:81:81:System Message Bus:/:/sbin/nologin
bin:x:1:1::/:/sbin/nologin
daemon:x:2:2::/:/sbin/nologin
mail:x:8:12::/var/spool/mail:/sbin/nologin
ftp:x:14:11::/srv/ftp:/sbin/nologin
http:x:33:33::/srv/http:/sbin/nologin
...

'{print $0}:awk对/etc/passwd的每一行都执行了print命令。
$0:上面说了$0代表一条记录,这里默认是/etc/passwd的每一行。

下面对一个复杂一点的命令进行解释,来直观的感受一下pattern字段分隔符的效果:

➜  ~ awk -F ":" '/^system.*$/{print $1}' /etc/passwd 
systemd-journal-remote
systemd-network
systemd-resolve
systemd-timesync
systemd-coredump

-F ":":指定分隔符为:。上面说过,默认记录的分割符是空格或者TAB。
/^system.*$/:正则表达式匹配system开头的记录。
{print $1}:输出每条记录的第一个字段。

上图解释一下:


image.png

2. BEGIN和END模块

2.1 BEGIN

awk在开始处理输入文件之前会执行BEGIN模块,所以它是初始化FS(字段分隔符)变量、打印页眉或初始化其它在程序中以后会引用的全局变量的极佳位置。

2.2 END

awk在处理完输入文件之后会执行END模块,通常,END块用于执行最终计算或打印应该出现在输出流结尾的摘要信息。

2.3 使用

统计/etc/passwd中帐号人数

➜  ~ awk 'BEGIN {count=0;print "[start] user count is", count} {count++;print $0} END {print "[end] user count is", count}' /etc/passwd
[start] user count is 0
root:x:0:0::/root:/bin/bash
nobody:x:65534:65534:Nobody:/:/sbin/nologin
dbus:x:81:81:System Message Bus:/:/sbin/nologin
...
[end] user count is 33

3. 内置变量

变量 含义
$0 整行记录
$1~$n 当前记录的第几个字段
FS 字段分隔符,默认是空格
RS 记录分隔符,默认是换行符
NF 当前行字段数目,就是有多少列
NR 已经读出的记录数,就是行号
OFS 输出字段分隔符,默认也是空格
ORS 输出记录分隔符,默认也是换行符

3.1 字段分隔符FS

  • FS="\t+"一个或多个TAB分隔
    ➜  ~ cat test
    awk     hello                           world!
    ➜  ~ awk 'BEGIN{FS="\t+"}{print $1,$2,$3}' test
    awk hello world!
    
  • FS="[[:space:]+]"一个或多个空格分隔(默认)
    ➜  ~ cat test
    awk hello      world!
    ➜  ~ awk 'BEGIN{FS="[[:space:]+]"}{print $1,$2,$3}' test      
    awk hello 
    ➜  ~ awk -F [[:space:]+] '{print $1,$2,$3}' test 
    awk hello
    
  • FS="[ :]+"一个或多个空格或者:分隔
    ➜  ~ cat test
    awk:hello world!
    ➜  ~ awk -F '[ :]+' '{print $1,$2,$3}' test
    awk hello world!
    ➜  ~ awk 'BEGIN {FS="[ :]+"} {print $1,$2,$3}' test           
    awk hello world!
    

3.2 字段数NF

输出字段数为2的记录

➜  ~ cat test
awk:hello:world
hell:world
➜  ~ awk -F ':' '{if(NF==2) print $0}' test
hell:world

3.3 记录数NR

输出第一条记录

➜  ~ cat test
awk:hello:world
hell:world
➜  ~ awk '{if(NR==1) print $0}' test
awk:hello:world

3.4 输出字段分隔符OFS

➜  ~ awk 'BEGIN {FS=":";OFS="QAQ"} {print $1,$2,$3}' test  
awkQAQhelloQAQworld
hellQAQworldQAQ

3.5 输出行分隔符ORS

➜  ~ awk 'BEGIN {FS=":";ORS="\nQAQ\n"} {print $0}' test 
awk:hello:world
QAQ
hell:world
QAQ

4. awk的if、循环和数组

4.1 条件语句

上面已经给了很多使用实例了,这里就不多说了

4.2 循环结构

  • while循环
    ➜  ~ vim script
    #!/bin/awk
    BEGIN {
        i=1
    }
    {
        while (i < 3) {
            print i
            i++
        }
        print $0
    }
    ➜  ~ awk -f script test
    1
    2
    awk:hello:world
    hell:world
    
  • for循环
    ➜  ~ vim script 
    #!/bin/awk
    {
            for (i=1;i<4;i++) {
                    print i
            }
    }
    ➜  ~ cat test
    awk:hello:world
    hell:world
    ➜  ~ awk -f script test
    1
    2
    3
    1
    2
    3
    # 因为test有两行,每一行执行一次script,所有输出了两次1 2 3
    

4.3 数组

awk中的数组都是关联数组,数字索引也会转变为字符串索引

➜  ~ vim script        
#!/bin/awk
{ 
        cities[1]="beijing"
        cities[2]="shanghai"
        cities["three"]="guangzhou"
        for( c in cities) {
                print cities[c]
        }
        print "---"
        print cities[1]
        print cities["1"]
        print cities["three"]
}
➜  ~ cat test
awk:hello:world
➜  ~ awk -f script test
guangzhou
beijing
shanghai
---
beijing
beijing
guangzhou

查看网络汇总状态

➜  ~ netstat -an | awk '/^tcp/ {s[$NF]++} END {for (i in s) print i,s[i]}'
LISTEN 20
ESTABLISHED 5

5. 案例

5.1 两个文件求交集

➜  ~ cat a
1,name
2,name
3,name
4,name
5,name
6,name
➜  ~ cat b
3,city
6,city
7,city
➜  ~ vim script                       
#!/bin/awk
BEGIN {
        FS=","
}
{
        if (NR==FNR) {
                a[$1]++
        }
        if (NR>FNR) {
                if ($1 in a) {
                        print $0
                }
        }
}
➜  ~ awk -f script a b                
3,city
6,city

脚本解释:
BEGIN{FS=","}:很简单了,指定分隔符。
if (NR==FNR) {a[$1]++}:这里是把第一个文件的第一列作为数组的索引,将它出现的次数作为值。
if (NR>FNR) {if ($1 in a) {print $0}}:这里是查看第二个文件当前第一列是否在上面的数组中,如果存在则输出。
重点解释:FNR
NR都已经明白是awk已经读出的记录数,就是行号。
FNR,与NR类似,但是不同的是每当awk打开一个新文件时,FNR便重新计数;而NR是继续计数。
举例:

  • 只打开一个文件时,两者没有什么区别
    ➜  ~ awk '{print NR,$0}' t1   
    1 a
    2 b
    3 c
    4 d
    5 e
    6 f
    ➜  ~ awk '{print FNR,$0}' t1 
    1 a
    2 b
    3 c
    4 d
    5 e
    6 f
    
  • 但是当打开多个文件呢?
    ➜  ~ awk '{print NR,$0}' t1 t2 
    1 a
    2 b
    3 c
    4 d
    5 e
    6 f
    7 a
    8 b
    9 c
    ➜  ~ awk '{print FNR,$0}' t1 t2 
    1 a
    2 b
    3 c
    4 d
    5 e
    6 f
    # 这里打开t2文件时,行号重新计数了
    1 a
    2 b
    3 c
    
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,699评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,124评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,127评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,342评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,356评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,057评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,654评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,572评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,095评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,205评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,343评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,015评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,704评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,196评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,320评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,690评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,348评论 2 358

推荐阅读更多精彩内容

  • 转载 原文的排版和内容都更加友好,并且详细,我只是在这里贴出了一部分留作自己以后参考和学习,如希望更详细了解AWK...
    XKirk阅读 3,221评论 2 25
  • 本章主要学习内容awk介绍 awk基本用法 awk变量 awk格式化 awk操作符 awk条件判断 a...
    楠人帮阅读 1,271评论 0 8
  • Linux指令中文说明传送入口 整理自Linux指令中文说明 文本和数据进行处理的编程语言awk 是一种编程语言,...
    释闲人阅读 2,129评论 1 6
  • awk介绍awk变量printf命令:实现格式化输出操作符awk patternawk actionawk数组aw...
    哈喽别样阅读 1,569评论 0 4
  • 有位朋友和我诉苦,最近失恋了,说自己怎么总是碰到渣男,爱情路上屡屡不顺。我问上一段恋情是因为什么分开的呢?她说:“...
    默艺青阅读 507评论 0 0