文本三剑客之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

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。