文本三剑客之awk

awk基本用法

awk [-F"分隔符" | -v var=value ] 'BEGIN{action}/pattern/{action}END{action}' file ...

awk工作原理
  1. 第一步
  • 执行BEGIN{action;… }语句块中的语句
  • BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,
    比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中
  1. 第二步
  • 从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕
  • pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块
  1. 第三步
  • 当读至输入流末尾时,执行END{action;…}语句块
  • END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块

选项

  • -F "分隔符" # 分隔符可以使用正则表达式
df | awk -F " +|%" '{print $1,$5}'
  • -v var=value 变量赋值

awk变量

内置变量

  1. FS:输入字段分隔符,默认为空白符
awk -v FS=':' '{print $1,FS,$3}' /etc/passwd
  1. OFS:输出字段分隔符,默认为空白符
awk -v FS=':' -v OFS=':' '{print $1,$3,$7}' /etc/passwd
  1. RS:输入记录分隔符,指定输入时的换行符
awk -v RS='' '{print}' /etc/passwd
  1. ORS: 输出记录分隔符,输出时用指定符号代替换行符
awk -v RS='' -v ORS='###' '{print}' /etc/fstab
  1. NF:字段数量
awk -F: '{print NF}' /etc/fstab
awk -F: '{print $(NF-1)}' /etc/passwd
  1. NR:记录号
awk END‘{print NR}’ /etc/fstab
awk END'{print NR}' /etc/fstab
  1. FNR: 各文件分别计数,记录号
awk '{print FNR}' /etc/fstab /etc/inittab
  1. FILENAME:当前文件名
awk '{print FILENAME}' /etc/fstab
  1. ARGC: 命令行参数的个数
awk '{print ARGC}' /etc/fstab /etc/inittab
awk 'BEGIN {print ARGC}' /etc/fstab /etc/inittab
  1. ARGV: 数组,保存的是命令行所给定的各参数
awk 'BEGIN {print ARGV[0]}' /etc/fstab /etc/inittab
awk 'BEGIN {print ARGV[1]}' /etc/fstab /etc/inittab

自定义变量

  1. -v var=value
awk -v test='hello gawk' '{print test}' /etc/fstab
  1. 在program中直接定义
awk 'BEGIN{test="hello gaswk";print test}'
awk -F: '{sex="male";print $1,sex,age;age=18}' /etc/passwd

Pattern

awk PATTERN

根据pattern过滤匹配的行 awk '/pattern/{}'

  1. /regular expression/
  2. relational expression
  3. line ranges /pat1/,/pat2/

Action

  1. Expression:算术,比较表达式
  2. control statement: if, while
  3. compound statements:组合语句
  4. input statements
  5. output statements: print等

awk格式化 printf

格式

printf "FORMAT", item1, item2, ...

Format comments
格式符
%c 显示字符的ASCII码
%d, %i 显示十进制整数
%e,%E 显示科学计数法数值
%f 显示浮点数
%g, %G 以科学计数法或浮点形式显示数值
%s 显示字符串
%u 无符号整数
%% 显示%
修饰符
#[.#] 第一个数字控制显示宽度;第二各数字表示小数点后精度
- 左对齐
+ 显示数值的正负号
[root@test1_c1 data]#awk -F: '{printf "%s", $1}' /etc/passwd
rootbindaemonadmlpsyncshutdownhaltmailoperatorgamesftpnobodysystemd-networkdbuspolkitdlibstoragemgmtabrtrpcsshdpostfixchronyntptcpdumpapachesaslauthwangxiangmysqlxingabcuser1user2user3user4user5user6user7user8user9user10
[root@test1_c1 data]#awk -F: '{printf "%s\n", $1}' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
[root@test1_c1 data]#awk -F: '{printf "%-20s %10d\n",$1,$2}' /etc/passwd
root                          0
bin                           0
daemon                        0
adm                           0
lp                            0
sync                          0
shutdown                      0
halt                          0
mail                          0
operator                      0
games                         0
[root@test1_c1 data]#awk -F: '{printf "Username: %s,UID:%d\n",$1,$3}' /etc/passwd
Username: root,UID:0
Username: bin,UID:1
Username: daemon,UID:2
Username: adm,UID:3
Username: lp,UID:4
Username: sync,UID:5
Username: shutdown,UID:6
Username: halt,UID:7
Username: mail,UID:8
Username: operator,UID:11
Username: games,UID:12
[root@test1_c1 data]#awk -F: '{printf "Username:%15s,UID:%d\n",$1,$3}' /etc/passwd
Username:           root,UID:0
Username:            bin,UID:1
Username:         daemon,UID:2
Username:            adm,UID:3
Username:             lp,UID:4
Username:           sync,UID:5
Username:       shutdown,UID:6
Username:           halt,UID:7
Username:           mail,UID:8
Username:       operator,UID:11
Username:          games,UID:12
[root@test1_c1 data]#awk -F: '{printf "Username:%-15s, UID:%d\n",$1,$3}' /etc/passwd
Username:root           , UID:0
Username:bin            , UID:1
Username:daemon         , UID:2
Username:adm            , UID:3
Username:lp             , UID:4
Username:sync           , UID:5
Username:shutdown       , UID:6
Username:halt           , UID:7
Username:mail           , UID:8
Username:operator       , UID:11
Username:games          , UID:12

awk操作符

算术操作符
  1. x+y, x-y,x*y,x/y,x^y,x%y
    2 - x : 转换为负数
  2. +x:将字符串转换为数值
字符串操作符
赋值操作符

=,+=,-=,*=,/=,%=,^=,++,--

[root@test1_c1 scripts]#awk 'BEGIN{i=0;print ++i,i}'
1 1
[root@test1_c1 scripts]#awk 'BEGIN{i=0;print i++,i}'
0 1
比较操作符

==,!=,>,>=,<,<=

模式匹配符
  • ~: 左边是否和右边匹配,包含
  • !~:是否不匹配
逻辑操作符

&&,||,!

awk -F: '$3>=0 && $3<=100{print $1}' /etc/passwd
awk -F: '$3==0 || $3>=1000{print $1}' /etc/passwd
awk -F: '!($3==0){print $1}' /etc/passwd
awk -F: '!($3>=500){print $3}' /etc/passwd
条件表达式

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

awk -F: '{$3>=1000?usertype="Common User":usertype="Sysuser"; \
        printf "%15s:%-s\n",$1,usertype}' /etc/passwd

awk控制语句

组合语句

{statements1;statements2;...}

条件

对awk取得的整行或某个字段做条件判断

  • if(condition) {statements;...}
  • if(condition) {statements;...} eles {statements;...}
  • switch(expression){case VALUE1 or /REGEXP/: statement1; /
    case VALUE2 or /REGEXP2: statement2; /
    ......
    default: statemens}
df | awk -F " +|%" '/^\/dev\//{if($5>10){printf "Disk %s utility %d  above 80%\n",$1,$5}else{printf "Disk %s is safe\n", $1}}'
循环

对一行内多个字段逐一类似处理
对数值各元素逐一处理

  • while(condition) {statements; ...}
  • do {statements; ...} while(condition)
  • for(expr1;expr2;expr3) {statements; ...}
  • for(var in array) {for-body}
  • break
  • continue
  • next
    提前结束对本行处理而直接进入下一行处理
awk '/linux16/{i=1;while(i<=NF){print $i,length($i);i++}}' /boot/grub2/grub.cfg
awk -v sum=0 'BEGIN{i=1;while(i<=100){sum+=i;i++};print sum}'
awk 'BEGIN{sum=0;for(i=1;i<=100;i++){sum+=i}print "sum="sum}'

[root@test1_c1 scripts]#time seq -s+ 100000 | bc
5000050000
real    0m0.040s
user    0m0.039s
sys 0m0.003s
[root@test1_c1 scripts]#time awk -v sum=0 'BEGIN{i=1;while(i<=100000){sum+=i;i++};print sum}'
5000050000
real    0m0.011s
user    0m0.010s
sys 0m0.001s
[root@test1_c1 scripts]#time awk 'BEGIN{sum=0;for(i=1;i<=100000;i++){sum+=i}print "sum="sum}'
sum=5000050000
real    0m0.010s
user    0m0.008s
sys 0m0.002s

数组

关联数组:array[index-expression]

index-expression
  1. 可以使用任意字符串;字符串用双引号括起来
  2. 如果数组元素不存在,引用其时,awk自动创建此元素,并初始化为空串
  3. 遍历数组
    for(var in array) {for-body} # var为数组下标
  4. 删除数组元素和数组
  • delete array[index]
  • delete array
# 去重打印
awk '!a[$0]++' data.txt
#统计每个ip出现的此时
awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' access_log

ss -nat | awk '! /^State/{state[$1]++}END{for(i in state){print i,state[i]}}'

函数

自带函数
  1. 数值处理 rand()返回0和1之间一个随机数
awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }'
  1. 字符串处理
  • length([s])
  • sub(r,s,[t]): 对t字符串搜索r表示模式匹配的内容,并将第一个匹配内容替换为s
  • gsub(r,s,[t]): 对t字符串搜索r表示模式匹配的内容,并全部替换为s
  • split(s,array,[r]): 以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组,第一个索引为1,第二个索引为2
自定义函数

function name (parameter1, parameter2, ...) {
statements
return expression
}

调用系统命令 system

  1. 空格是awk中的字符串连接符,除了awk中的变量外其它一律用""

awk脚本

向awk脚本传递参数

awkfile var=value var2=value2.... inputfile

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