# awk

AWK 是一种处理文本文件的语言,是一个强大的文本分析工具。

之所以叫 AWK 是因为其取了三位创始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。

# 命令格式

awk [选项参数] 'script' var=value file(s)
# 或
awk [选项参数] -f scriptfile var=value file(s)

默认情况下会遍历每一行进行处理,也可以通过加入匹配规则来对指定的数据进行处理。

# BEGIN 后面大括号中的指令会在正式处理文本之前执行,对应 END 后面括号中的指令会在文本处理完之后执行
# patter 就是指定的匹配规则,默认是每一行,匹配之后会使用其后指定的 commands 去处理
# 在括号中,多个命令可以使用分号进行分割
awk 'BEGIN{}patter{commands}END{}' file_name

# 内置变量

Awk 是一种便于使用且表达能力强的程序设计语言,可应用于各种计算和数据处理任务,其中内置了一些变量。

变量 含义
$0 整行内容
NF 当前行的经分隔符分割后的字段个数,也就是有多少列
$1-$n 当前行的第 1-n 个字段
NR 当前行的行号,从 1 开始计数,多文件时会累加
FNR 多文件处理时,每个文件行号单独计数,都是从 0 开始
FS 输入分割字段符,默认以空格或 Tab 键分割
RS 输入行分隔符,默认回车换行
OFS 输出字段分隔符
ORS 输出行分隔符
FILENAME 当前输入文件的名字
ARGC 命令行参数个数
AGRV 命令行参数数组
$ cat test.txt
1
2
3

$ awk '{print $0}' test.txt
1
2
3

# 内置函数

Awk 除了内置了一些变量之外,内置了一些常用的函数。

函数 功能
rand() 返回任意数字 n,其中 0 <= n < 1
length[(String)] 返回 String 参数指定的字符串的长度(字符形式)
$ cat test.txt
1
2
3

$ awk '{print rand()}' test.txt
0.840188
0.394383
0.783099

# 格式化输出

打印输出时,printf 包括一个加引号的控制串,控制串中可能嵌有若干格式说明和修饰符。

格式符 用途
%s 打印字符串
%d 打印十进制数
%f 打印一个浮点数
%x 打印十六进制数
%o 打印八进制数
%e 打印数字的科学计数法形式
%c 打印单个字符的 ASCII 码
- 打左对齐
+ 右对齐
# 显示进制前缀
$ cat test.txt
1
2
3

$ awk '{printf $0}' test.txt
123

$ awk '{printf "%+9s\n",$0}' test.txt
        1
        2
        3

# 常用选项

# 指定输入文件折分隔符(相当于内置变量 FS),fs 是一个字符串或者是一个正则表达式,如 -F:
-F fs or --field-separator fs

# 从脚本文件中读取命令
-f scripfile or --file scriptfile

# 定义一个 awk 变量并赋值,可以将外部变量传递给 awk
-v, --assign VAR=VAL

# 匹配模式

匹配模式主要包含正则匹配和关系运算匹配两种。

# 匹配 /etc/passwd 文件中以 root 开头的行
awk '/^root/{print $0}' /etc/passwd

常见的运算符包括:

符号 说明
> 大于
< 小于
== 等于
~ 匹配指定的正则表达式
|
&
!
# 以冒号为字段分隔符,匹配 /etc/passwd 文件中第 3 个字段大于 50 的行
awk 'BEGIN{FS=":"}$3>50{print $0}' /etc/passwd

# 以冒号为字段分隔符,匹配 /etc/passwd 文件中第 3 个字段包含 3 个以上数字的行
awk 'BEGIN{FS=":"}$3~/\d{3,}/{print $0}' /etc/passwd

# 案例

求给定数据每行的平均值。

$ cat score.txt
Marry   2143 78 84 77
Jack    2321 66 78 45
Tom     2122 48 77 71
Mike    2537 87 97 95
Bob     2415 40 57 62

$ cat cal.awk
# 运行前
BEGIN {
    math = 0
    english = 0
    computer = 0

    printf "NAME    NO.   MATH  ENGLISH  COMPUTER   TOTAL\n"
    printf "---------------------------------------------\n"
}
# 运行中
{
    math+=$3
    english+=$4
    computer+=$5
    printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5
}
# 运行后
END {
    printf "---------------------------------------------\n"
    printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR
}

$ awk -f cal.awk score.txt
NAME    NO.   MATH  ENGLISH  COMPUTER   TOTAL
---------------------------------------------
Marry  2143     78       84       77      239
Jack   2321     66       78       45      189
Tom    2122     48       77       71      196
Mike   2537     87       97       95      279
Bob    2415     40       57       62      159
---------------------------------------------
AVERAGE:     63.80    78.60    70.00