awk 使用示例

awk 是一种编程语言,用于在 linux/unix 下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是 linux/unix 下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk 有很多内建的功能,比如数组、函数等,这是它和 C 语言的相同之处,灵活性是 awk 最大的优势。

awk 脚本基本结构

awk 'BEGIN{ commands } pattern{ commands } END{ commands }'

一个 awk 脚本通常由: BEGIN 语句块能够使用模式匹配的通用语句块END 语句块 3 部分组成,这三个部分是可选的。任意一个部分都可以不出现在脚本中,脚本通常是被放置在 单引号

awk 的工作原理

  1. 执行 BEGIN{ commands } 语句块中的语句;
  2. 从文件或标准输入(stdin)读取一行,然后执行 pattern{ commands } 语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
  3. 当读至输入流末尾时,执行 END{ commands } 语句块。

BEGIN语句块 在 awk 开始从输入流中读取行 之前 被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在 BEGIN 语句块中

END语句块 在 awk 从输入流中读取完所有的行 之后 即被执行,比如打印所有行的分析结果这类信息汇总都是在 END 语句块中完成,它也是一个可选语句块。

pattern语句块 中的通用命令是最重要的部分,它也是可选的。如果没有提供 pattern语句块 ,则默认执行 { print } ,即打印每一个读取到的行, awk 读取的每一行都会执行该语句块

awk 内置变量(预定义变量)

变量 说明 示例
$0 当前行的整行内容 '{print $0}' 打印出当前处理行的整行内容
$n 当前记录(行)的第 n 个字段 '{print $1}' 打印出当前行的第 1 个字段
NR 当前处理行的行号(第多少行) '{print NR,$1}' END{print NR} 打印出当前处理行的行号和第 1 列,最后打印出总的行号
FNR 当前处理行在当前处理文件中的行号,只有 1 个输入文件时,NR=FNR
NF 当前行的字段数 '{print NF,$NF,$(NF-1)}' 输出当前行的字段数,最后一个字段 ,倒数第 2 个字段
FILENAME 当前输入文件的文件名, - 表示 stdin '{print FILENAME,FNR}' 打印当前处理的文件名及当前行号
FS 输入字段分隔符,等同于选项 -F ,默认为空格
OFS 输出字段的分隔符,默认为空格 'BEGIN{OFS="|"} {print FILENAME,FS,NR,NF,$2,$NF}' 输出结果将会以 | 分割
RS 输入记录分隔符(行分隔符),默认为换行
ORS 输出记录分隔符(行分隔符),默认为换行

awk 常用选项

选项 说明 示例
-F"sep"
-F"[,.]"
等同于内置变量 FS ,有 2 种格式:
-F"sep" 使用 sep 整体作为字段分隔符
-F[,.] [] 其中的每个字符都可以作为分隔符
等同于 BEGIN 预定义变量 FS
-v var=1 传递用户自定义变量给 awk awk -va=1 -vb=2 '{print a+b}'

awk 常用运算符

运算符 说明 示例
=
+=
-=
*=
/=
%=
^=
**=
赋值
~
!~
匹配正则表达式
不匹配正则表达式
awk '$2 ~ /th/ {print $2,$4}' log.txt 第 2 列中包含 ‘th’,则输出第 2,4 列
awk 'BEGIN{IGNORECASE=1} /this/' log.txt 忽略大小写匹配
awk '$2 !~ /th/ {print $2,$4}' log.txt 不匹配正则表达式
<
<=
>
>=
!=
==
关系运算符 awk '$1>2' log.txt 第 1 列的值大于 2,输出整行
awk '$1==2 {print $1,$3}' log.txt 第 1 列的值等于 2,则输出第 1,3 列
+
-
*
/
%
加,减,乘,除与求余
+
-
!
一元加,减和逻辑非
| | 逻辑或
&& 逻辑与 awk '$1>2 && $2=="Are" {print $1,$2,$3}' log.txt 第 1 列大于 2,并且第 2 列等于 “Are”,则输出第 1,2,3 列

awk 常用用法示例

每一行中第个字段值累加

awk
seq 1 10 | awk 'BEGIN{sum=0;print "第1列求和"}{sum+=$1}END{print "sum="sum}'

第 1 列求和
sum=55

判断 2 列的内容是否相同

awk
awk '{if($1==$2){print $1}}'

找出字段数(列数)大于 3 的行

awk 'NF>3{print $0}' 

参考链接

参考文章