Linux-grep、sed、awk之awk命令

参考:
Linux三剑客(grep sed awk) 之 awk
awk从放弃到入门
The GNU Awk User’s Guide

awk是一个报告生成器,支持条件判断、数组、循环等功能,可以将文本整理成我们想要的表格形式。awk逐行处理,默认按照空格作为分隔符,若有多个空格,则将连续的空格作为分隔符。

一、awk基础

  1. 普通模式
awk [options] 'program' file1,file2

program = pattern+action

awk [options] 'Pattern{Action}' file

awk常用动作为print和printf

  1. 特殊模式
awk 'BEGIN{coms}/pattern/{coms}END{coms}'

1)BEGIN和END模块只能有一个,中间的pattern匹配可以有多个
2)BEGIN:代表awk在处理文本前要做的事情,即使无文件名,仅用BEGIN也能正常输出

awk 'BEGIN{print "111","222"}'

3)END:代表awk在处理文本后要做的事

awk '{print 1,2}END{print'333','444'}'test
  1. 内置变量
变量名 属性 备注
$0 当前一整行
$1~$n 当前记录的第n个字段 awk '{print "str:"$1'}'
FS 输入字段分隔符,默认为space awk -F ':' awk -v FS=':'
RS 输入记录分隔符,默认为\n 如果RS=“”,会以空白行分隔
OFS 输出字段分隔符,默认space
ORS 输出的记录分隔符,默认\n
NF 当前记录中的字段个数,即多少列
NR 行号,从1开始
FNR 各文件分别显示行号
FILENAME 当前文件名 awk '{print FILENAME,$0}'
ARGC 命令行参数的个数
ARGV 数组,保存的是命令行给定的参数 ARGV[0]是awk,单引号中的不算参数,处理的文件是参数
  1. 自定义变量
    1)-v varname=value
$awk -v myVar="test" 'BEGIN{print myVar}'
$abc=666
$awk -v myvar=$abc 'BEGIN{print myvar}'

2)在program中定义

awk 'BEGIN{myvar="ttt";print myvar}'

tips:赋值时不要在等号左右加空格,我写R的时候习惯性啥都加空格,于是就报错啦

二、printf

  1. echo和printf
    两者都是输出文本命令,echo输出字符串末尾会自动加上\n;printf则不会,\n需要指定。
    printf的优势在于可以用格式替换符来处理一长串的str

格式替换符

名称 含义
%s 字符串
%f 浮点格式
%b 对应参数包含转义字符时,对应转义字符会被转义
%c ASCII字符,显示对应擦书第一个字符
%d,%i 十进制整数
%o 不带正负号的八进制值
%u 不带正负号的十进制值
%x 不带正负号的十六进制值,用af表示1015
%X 不带正负号的十六进制,用AF表示1015
%% 表示‘%’本身
转义字符
名称 含义
\a 警告字符,常为ASCII的BEL字符
\b 后退
\c 不显示
\f 换页
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
\\ “\”本身
\ddd 表示1~3位数八进制的字符串,仅在字符格式串中有效
\0ddd 表示1~3位数八进制值的字符串
修饰符
参数 含义
%7s 7代表当前替换符对应的输出长度为7个字符宽,不足补齐,超出也正常显示
%-7s “-”表示左对齐,不加时为右对齐
%+5d 正数会自动变为+num
%12.3f “.3”表示保留小数点后三位,%f默认是小数点后6位
%12.5d “.5”表示正数的长度,不足用0补齐
  1. awk的printf动作
    注意:
    输出文本不会换行,要手动加\n;
    “指定的格式”与“被格式化的文本”间要用“逗号”隔开
    “格式替换符”与“被格式化的文本”数量一一对应
$ awk -v FS=':' 'BEGIN{printf "%-10s\t %s\n","用户名称","用户ID"} {printf "%-10s\t %s\n",1,3}' /etc/passwd
用户名称         用户ID
1                3
1                3
1                3

三、awk模式(Pattern)

  1. grep和awk
grep '^root' /etc/password
awk '/^root/{print $0}' /etc/passwd
  1. 注意
    1)awk中的正则是扩展正则表达式
    2)在使用{x,y}或[[:space]]时,要加上参数--posix
    3)注意""和"."的转义

3.awk行范围模式

awk '/正则表达式/{动作}'  file
awk '/正则1/,/正则2/{动作}' file

两个正则就是行范围模式,从正则1匹配的行开始,到正则2匹配的行结束

匹配符 含义
~ 匹配后面的正则 '$1~/pattern/'
!~ 不匹配后面的正则 '$1!~/pattern/'

示例

$ cat test.txt
sdsfhu
djfia
I love you
I hate you
Oh/my god
$ awk '/^Oh\//{print $0}' test.txt
Oh/my god
$ awk --posix '/[[:space:]]/{print $0}' test.txt
I love you
I hate you
Oh/my god
$ awk '/love/,/hate/{print $0}' test.txt
I love you
I hate you
$ awk 'NR>=2 && NR<=4{print $0}' test.txt
djfia
I love you
I hate you

四、awk动作总结

{}:“组合语句”类型的动作,将多个代码组合成代码块
print $0:“输出语句”类型

  1. if动作
$ awk '{if(NR == 1){print $0}}' test.txt
sdsfhu
#if对应的{},若只有一条命令,可以省略{}
$ awk '{if(NR == 1) print $0}' test.txt
sdsfhu
$ awk '{if(NR == 1){print $1;print $2}}' test.txt
$ awk -F ":" '{if($3 <500){print $1,"系统用户"}else {print $1,"普通用户"}}' file
  1. for
$ awk 'BEGIN{for(i=1;i<=6;i++){print i}}'
1
2
3
4
5
6

3.while

$ awk -v i=1 'BEGIN{while(i<=5){print i;i++}}'
1
2
3
4
5
$ awk 'BEGIN{i=1;while(i<=5){print i;i++}}'
1
2
3
4
5
  1. do...while
#打印1遍test
$ awk 'BEGIN{i=1;do{print "test";i++}while(i<1)}'
test
#打印5遍test
$ awk 'BEGIN{do{print "test";i++}while(i<=5)}'
test
test
test
test
test
test
  1. continue和break
#打印0~5,但不打印3
$ awk 'BEGIN{for(i=0;i<6;i++){if(i==3){continue};print i}}'
0
1
2
4
5
#打印0~2
$ awk 'BEGIN{for(i=0;i<6;i++){if(i==3){break};print i}}'
0
1
2
  1. exit
    表示跳过所有后续动作,直接执行END内的命令;如果没有END模式,则直接结束awk命令
#只打印1
$ awk 'BEGIN{print 1;exit;print 2;print 3}'
1
#不打印$0
$ awk 'BEGIN{print "start";exit} {print $0} END{print "over"}' test.txt
start
over
  1. next
    跳过当前行,直接从下一行开始处理
#跳过第二行
$ awk '{if(NR==2){next};print $0}' test.txt
sdsfhu
I love you
I hate you
Oh/my god

这些命令感觉和C语言中的差不多~

五、awk数组

  1. 基础概念
    1)awk中数组是一个使用字符串作为下标的“关联数组”
    2)使用时可用数字/字符串作为下标,使用数字作为下标时,awk默认把“数字”下标转换为“字符串”
    3)awk中,元素值可以设置为“空”
    4) 当一个元素不存在于数组时,若直接引用这个不存在的元素,awk会自动创建这个元素,并默认为这个元素赋值为“空字符串”
    5) awk中,判断数组元素中是否存在,用“if(下标 in 数组名)”
    6)split函数生成的数组,下标默认从1开始
  2. 基本操作
#创建数组,可直接创建
$ awk 'BEGIN{ a[0]="一";a[1]="二";a[2]="三";print a[0]}'
一
#删除数组元素
$ awk 'BEGIN{a[0]="一";a[1]="二";a[2]="三";delete a[0]}'
#删除整个数组
$ awk 'BEGIN{a[0]="一";a[1]="二";a[2]="三";delete a}'
#for循环有序遍历数组,下标需要是数字
$ awk 'BEGIN{a[0]="一";a[1]="二";a[2]="三";for(i=1;i<=2;i++){print i,a[i]}}'
1 二
2 三
#for循环无序遍历数组
$ awk 'BEGIN{a[0]="一";a[1]="二";a[2]="三";for(i in a){print i,a[i]}}'
0 一
1 二
2 三

六、awk内置函数

  1. 算术函数
    1)rand 生成随机数
    2)srand 固定打印1,与rand合用可生成小于1的随机数
    3)int 取整
awk 'BEGIN{srand();print rand()}'
#随机数乘以100,通过int函数调整,生成0~100间的随机数
awk 'BEGIN{srand();print int(100*rand())}'
  1. 字符串函数
    1)gsub:将指定范围内匹配到的字符全部替换为新字符
    2)sub:与gsub类似,但只能替换范围内第一次匹配到的字符
awk '{gsub("you","me",1);print 0}' test.txt
awk '{sub("you","me");print }' test.txt

3)length:获取指定字符串长度
4)index:获取指定字符串位于整个字符串中的位置
5)split:返回数组长度

  1. 排序函数
    1)asort:根据数组value值进行排序。排序后,原有key会被数字替代
    2)asorti:排列原数组

七、三元运算

语法
条件?结果1:结果2

1.三元运算替换if…else

#if...else
awk -F : '{if($3<500){usertype="系统用户"}else{usertype="普通用户"};\print $1,usertype}' /etc/password
#三元运算符
awk -F : '{usertype=$3<500?"系统用户":"普通用户";\print 
$1,usertype}' /etc/passwd

$3<500:条件判断
?"系统用户":为真,则usertype=系统用户
:"普通用户":为假,则usertype=普通用户

#统计系统用户和普通用户数量
awk -F : '{$3<500?a++:b++}END{print a,b}' /etc/passwd
  1. 打印奇数偶数行
#打印奇数行
$ awk 'i=!i' test.txt
sdsfhu
I love you
Oh/my god
#打印偶数行
$ awk '!(i=!i)' test.txt
djfia
I hate you

解析
1)awk中,若省略了模式对应的动作,当前行满足模式时,默认动作为打印整行,即{print $0}
2)awk中,0或者空字符串表示“假”,非0值或者非空字符串表示“真”

$ awk '/o/{print $0}' test.txt
I love you
I hate you
Oh/my god
$ awk '/o/' test.txt
I love you
I hate you
Oh/my god

从上可看出,若省略了对应动作,默认输出整行,即'{print $0}'。BEGIN/END模式除外
那么将模式替换为“真”或“假”

接下来的可以自仔细琢磨参考博文的内容:https://www.zsythink.net/archives/2159
我自己讲不清楚了/捂脸,慢慢悟吧呜呜

$ awk '{i=!i;print i}' test.txt
1
0
1
0
1

可以看到,打印出i值,第一行为1,;然后再取反值,则为0
因此,在打印奇数行时,因为i最开始不为0,所以这一行被打印
(我也被自己绕晕了,总之就是这样能打印出来奇数行。。)
偶数行同理,只不过是再取一个反值

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

推荐阅读更多精彩内容