Linux三剑客之awk

Linux三剑客之awk
awk简介
awk,全称GNU awk
此命令的设计者有 3 位,他们的姓分别是 Aho、Weingberger 和 Kernighan,awk 就取自这 3 为大师姓的首字母。
awk不仅仅是Linux中的一个命令,而且还是一种编程语言,可以用来处理和生成报告(excel)。它是Linux中最强大的文本处理工具,没有之一。
[root@m01 ~]#ls -l `which awk`
lrwxrwxrwx. 1 root root 4 Sep 9 18:10 /usr/bin/awk -> gawk
一般我们使用awk,都是当做命令使用,所以我们称之为单行脚本那么awk能不能写脚本呢,必然可以,在linux系统中就有很多的awk脚本
[root@m01 ~]# find /usr/share/ -type f -name '*.awk'
/usr/share/awk/assert.awk
/usr/share/awk/bits2str.awk
/usr/share/awk/cliff_rand.awk
...
awk语法格式
# 语法格式
awk [选项] '模式{动作1;动作2}' 文件
有多个动作时;隔开
# 选项
-F 指定分隔符
-v 传递命令行的变量 定义或修改一个awk内部的变量
# 简单例子
显示/etc/passwd行号,第一列,第三列和最后一列
[root@m01 ~]# awk -F: '{print $1,$3,$NF}' /etc/passwd
awk的模式和动作
模式
[root@m01 ~]# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
...
[root@m01 ~]# awk -F: 'NR==1{print$1,$3}' /etc/passwd //先取第1行,再取列
root 0
比如上面这条命令'NR==1{print $1,$3}'对应就是'模式{动作}' 相当于:'条件{指令}'
## 模式有:
# 比较表达式
NR==1
NR>=10
NR<=100
NR>=1 && NR<=10
$1>=100
比如,取etc/passwd的1-3行
[root@m01 ~]# awk 'NR<=3' /etc/passwd
# 范围模式
精确匹配行号:从第10行到第20行
NR==10,NR==20
[root@m01 ~]# awk 'NR==1,NR==3' /etc/passwd (效果同上)
# 精确匹配字符串:从该字符串的行到另一个字符串所在行
'/root/,/zls/'
'/从哪个字符串所在行/,/到那个字符串所在行/' #中间的行都包含进去
比如:取出包含root的行,要讲要取的内容用//包含
[root@m01 ~]# awk '/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
# 模糊匹配字符串:从含有该字符串所在行到含有另一字符串所在行
'$1~/oo/,$1~/zl/'
## 正则表达式模式
# 正则表达式写法 也是用//包含
'/正则表达式/flag'
'$1~/正则表达式/flag'
'$1!~/正则表达式/flag'
只不过我们在awk中很少使用flag
## 特殊模式:
BEGIN 和 END
动作
- print 打印
- gsub 替换
- gsub/被替换的内容/,"要替换的" ,$n指定要替换的列
- 变量赋值
- 统计计算
有多个动作时用;隔开
awk的常见变量
内置变量 | 含义 |
$0 | 当前整行记录 |
$n | 当前记录的第n个列,字段间由FS或-F选项指定分隔符 |
NF | Number of Field 所有列数。即共有多少列 |
$(NF-n) | 倒数第n+1列 |
NR | Number of Record 已经读出的记录数,就是行号。从1开始 |
RS | Record Separator -vRS可指定每行(每个记录)结束的标识,默认是回车(换行符) |
FS | Field Separator -vFS(-F)指定读取列时的分隔符(默认是空格) |
OFS | Output Field Separator 输出时候的分隔符,默认是空格 |
awk执行流程
- 读取文件前
- BEGIN{} - 读取文件之前,先判断命令的选项:-F,-v
- 如果写了BEGIN{},再执行BEGIN{}里面的动作 - 读取文件时
- {}
- awk读取文件时(和sed一样),一行一行读取文件
- 读取一行之后,判断是否满足条件'NR==3{print $0}',满足后再执行{}中的动作
- 如果不满足条件,awk继续读取下一行,直到满足条件或者到文件的最后一行
- 读取文件后
- END{}完成读取所有文件后,执行END{}里面的动作
任写哪个阶段都行,但END阶段不能单独使用
[root@m01 ~]# awk 'BEGIN{print 1+3}'
4
[root@m01 ~]# awk 'END{print 1+3}' 不行,后面要有文件名
注意:awk中单引号和双引号区别很大,双引号引字符串,单引号调用awk的变量
# 坑,在awk无法直接调用bash变量
[root@m01 08:59:36 ~]# awk "/$HOSTNAME/{print $1}"
必须外面单引号里面双引号
[root@m01 ~]# awk -F: 'BEGIN{print "用户名","UID"}{print $1,$3}END{print "文件读取完毕"}' /etc/passwd
用户名 UID
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
...
[root@m01 ~]# awk -F: 'BEGIN{print "用户名","UID"}{print $1,$3}END{print "文件读取完毕"}' /etc/passwd|column -t
用户名 UID
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
nobody 99
...