1 简介
awk
是一种强大的文本处理工具和编程语言,主要用于处理格式化文本数据。它由 Alfred Aho、Peter Weinberger 和 Brian Kernighan 开发,名字的来源是三位作者名字的首字母。awk
是类 Unix 系统中标配的工具之一。
2 命令格式
awk [options] 'pattern {action}' inputFile
- options: 命令参数
- pattern: 指定条件,决定应用哪些行。可以是正则表达式、条件表达式等。
- action:指定在匹配的行上执行的操作,通常是打印、修改、聚合等。
- input_file:要处理的文件或输入。
3 参数
awk
命令主要有以下参数:
参数 | 参数说明 |
---|---|
-F | 指定输入字段分隔符(FS ,Field Separator ),默认是空格或制表符。 |
-v | 在 awk 程序开始执行之前定义一个变量及其初始值。 |
3.1 -F 参数
-
作用:
-F
参数在awk
中用于指定输入的字段分隔符(FS
,Field Separator
)。通过它可以灵活地处理不同格式的文本文件,例如以逗号、冒号或其他符号分隔的文件。 -
例子1:指定分隔符为
","
,并提取 data.csv 的第1和第3行
[root@doc-nginx opt] # 生成 data.csv 文件
[root@doc-nginx opt] cat >data.csv<<EOF
> name,age,city
> Alice,30,New York
> Bob,25,Los Angeles
> Charlie,35,Chicago
> EOF
[root@doc-nginx opt] # 指定分隔符为 “,”, 并输出第1列及第3列
[root@doc-nginx opt] awk -F ',' '{print $1, $3}' data.csv
name city
Alice New York
Bob Los Angeles
Charlie Chicago
- 例子2:指定分隔符为
","
或||
,并输出第1列及第3列
[root@doc-nginx opt] cat data.csv
name,age||city
Alice,30||New York
Bob,25||Los Angeles
Charlie,35||Chicago
[root@doc-nginx opt]
[root@doc-nginx opt] awk -F ',|\\|\\|' '{print $1, $3}' data.csv
name city
Alice New York
Bob Los Angeles
Charlie Chicago
解释:
(1) data.csv 的 第1列 跟 第2列 用 ","
分隔,第2列 跟 第3列 用 ||
分隔。
(2) 使用正则表达式 ,|\|\|
指定分隔符,意思是,分隔符是逗号或 ||
。
3.2 -v 参数
-
作用:
-v
参数用于从命令行向awk
脚本传递变量值。这样可以在运行脚本时动态设置变量,而无需修改脚本本身 -
例子:读取
data.csv
,传入变量prefix
,并把prefix
变量与姓名一起打印出来
[root@doc-nginx opt] cat data.csv
name,age||city
Alice,30||New York
Bob,25||Los Angeles
Charlie,35||Chicago
[root@doc-nginx opt]
[root@doc-nginx opt] awk -F ',' -v prefix="Hello, " '{print prefix,$1}' data.csv
Hello, name
Hello, Alice
Hello, Bob
Hello, Charlie
[root@doc-nginx opt] awk -F ',' -v prefix="你好, " '{print prefix,$1}' data.csv
你好, name
你好, Alice
你好, Bob
你好, Charlie
4 变量
AWK 提供了一组预定义的内置变量,这些变量在脚本中非常有用,可以帮助我们轻松访问和操作输入数据、控制程序流程以及处理输出。
4.1 输入相关变量
变量 | 描述 |
---|---|
FS | Field Separator,输入字段分隔符,默认是空格或制表符。 |
RS | Record Separator,输入记录分隔符,默认是换行符。 |
FILENAME | 当前输入文件的名称。 |
NF | Number of Fields,当前记录的字段数。 |
NR | Number of Records,已处理的记录数(从第一个文件开始到当前记录)。 |
$0 | 当前记录的内容(整行)。 |
$1, $2, ..., $n | 当前记录的各个字段内容。 |
4.1.1 FS 变量
- 作用:输入字段分隔符,默认是空格或制表符
- 例子:读取
data.csv
,并指定分隔符为","
,在输出结果打印分隔符
[root@doc-nginx opt] awk -F ',' '{print "分隔符是",FS}' data.csv
分隔符是 ,
分隔符是 ,
分隔符是 ,
分隔符是 ,
4.1.2 RS 变量
- 作用:输入记录分隔符,默认是换行符
- 例子:指定记录分隔符变量
RS
为"#"
,然后把当前记录内容
[root@doc-nginx opt] cat >record.txt<<EOF
> hadoop#yarn#hive#spark#flink
> EOF
[root@doc-nginx opt] awk 'BEGIN {RS="#"} {print $0}' record.txt
hadoop
yarn
hive
spark
flink
4.1.3 NF
- 作用:当前记录的字段数
- 例子:输出记录内容 及 当前行的字段数
[root@doc-nginx opt] cat >record.txt<<EOF
> field_1 field_2
> field_1 field_2 field_3
> field_1 field_2 field_3 field_4
> EOF
[root@doc-nginx opt]
[root@doc-nginx opt] awk '{print $0,",有",NF,"字段"}' record.txt
field_1 field_2 ,有 2 字段
field_1 field_2 field_3 ,有 3 字段
field_1 field_2 field_3 field_4 ,有 4 字段
4.1.4 NR
- 作用:已处理的记录数
- 例子:输出 行号 及 记录内容
[root@doc-nginx opt] awk '{print NR,$0}' record.txt
1 field_1 field_2
2 field_1 field_2 field_3
3 field_1 field_2 field_3 field_4
4.2 输出相关变量
变量 | 描述 |
---|---|
OFS | Output Field Separator,输出字段分隔符,默认是空格。 |
ORS | Output Record Separator,输出记录分隔符,默认是换行符。 |
OFMT | Output Format,控制数值类型输出格式,默认是 %.6g(浮点数格式)。 |
CONVFMT | Conversion Format,数值转换为字符串的格式,默认是 %.6g。 |
4.2.1 OFS 变量
- 作用:用于指定输出时字段之间的分隔符。默认情况下,
OFS
的值是一个空格字符" "
。可以通过修改OFS
来改变字段之间的分隔符,例如使用逗号
、制表符
、竖线
等。 - 例子:读取文件,输出每一列内容,并用竖线
"|"
分隔
[root@doc-nginx opt] cat >fruit.txt<<EOF
> apple banana cherry
> grape orange mango
> EOF
[root@doc-nginx opt] awk 'BEGIN {OFS="|"} {print $1,$2,$3}' fruit.txt
apple|banana|cherry
grape|orange|mango
4.2.2 ORS 变量
- 作用:用于指定输出时记录之间的分隔符。默认情况下,
ORS
的值是换行符\n
。通过修改ORS
,可以改变输出记录之间的分隔符,例如使用空格、逗号或其他字符。 - 例子:将输出记录之间的分隔符设置为逗号。每条记录之间输出一个逗号而不是换行符
[root@doc-nginx opt] cat fruit.txt
apple banana cherry
grape orange mango
[root@doc-nginx opt] awk 'BEGIN {ORS="|"} {print $1,$2,$3}' fruit.txt
apple banana cherry|grape orange mango
4.2.3 OFMT 变量
- 作用:用于指定数字的输出格式。默认情况下,
OFMT
的值是%.6g
,表示输出最多6位有效数字(根据需要使用科学记数法或定点数)。通过修改OFMT
,可以改变数字输出的精度和格式,例如控制输出的小数位数、是否使用科学记数法等。 - 例子1:输出的结果固定2位小数
[root@doc-nginx opt] cat numbers.txt
123.456789
9876.54321
[root@doc-nginx opt]
[root@doc-nginx opt] awk 'BEGIN {OFMT="%.2f"} {print $1+0}' numbers.txt
123.46
9876.54
- 例子2:以科学记数法输出数字,保留3位小数
[root@doc-nginx opt] cat numbers.txt
123.456789
9876.54321
[root@doc-nginx opt]
[root@doc-nginx opt] awk 'BEGIN {OFMT="%.3e"} {print $1+0}' numbers.txt
1.235e+02
9.877e+03
5 pattern(模式)
在 AWK
中,pattern
(模式) 决定了哪些行会被处理。常见的 pattern 类型包括正则表达式、比较条件、范围模式、特殊模式(如 BEGIN
和 END
)、以及组合逻辑模式。
5.1 正则表达式模式
- 作用:匹配行中的文本。
- 语法:
/正则表达式/
- 例子1:
/apple/
匹配所有包含"banana"
的行。
[root@doc-nginx opt] cat >fruit.txt<<EOF
> apple banana cherry
> orange banana mango
> grape orange banana
> EOF
[root@doc-nginx opt] awk '/apple/' fruit.txt
apple banana cherry
- 例子2:匹配以特定单词开头的行
[root@doc-nginx opt] cat fruit.txt
apple banana cherry
orange banana mango
grape orange banana
[root@doc-nginx opt]
[root@doc-nginx opt] awk '/^orange/' fruit.txt
orange banana mango
5.2 关系运算模式
- 作用:基于
字段
或变量值
的比较条件。 - 语法:
表达式
- 例子1:匹配第一列的值大于10的行
[root@doc-nginx opt] cat >fruit.txt<<EOF
> 5 banana
> 15 orange
> 10 grape
> 20 cherry
> EOF
[root@doc-nginx opt] awk '$1 > 10' fruit.txt
15 orange
20 cherry
- 例子2:匹配第三列等于特定值的行
[root@doc-nginx opt] cat >data.txt<<EOF
> Alice 30 Female
> Bob 25 Male
> Charlie 35 Male
> EOF
[root@doc-nginx opt] awk '$3 == "Male"' data.txt
Bob 25 Male
Charlie 35 Male
- 例子3:匹配第三列等于
Male
且 第二列等于35
的行
[root@doc-nginx opt] cat data.txt
Alice 30 Female
Bob 25 Male
Charlie 35 Male
[root@doc-nginx opt] awk '$3 == "Male" && $2 == 35' data.txt
Charlie 35 Male
5.3 范围模式
- 作用:匹配
起始
和结束
模式之间的所有行
。 - 语法:
pattern1, pattern2
- 例子 1:匹配从第一列值为
5
到第一列值为10
的行
[root@doc-nginx opt] awk '$1 == 5,$1 == 10' fruit.txt
5 banana
15 orange
10 grape
- 例子2:匹配从单词
step
到单词end
的行
[root@doc-nginx opt] cat >log.txt<<EOF
> start processing
> step 1 complete
> step 2 complete
> end processing
> EOF
[root@doc-nginx opt] awk '/step/,/end/' log.txt
step 1 complete
step 2 complete
end processing
5.4 BEGIN 和 END 模式
- 作用:
BEGIN
在处理输入行之前
运行1
次,END
在处理完所有行之后
运行1
次。 - 语法:
BEGIN {actions}
或END {actions}
- 例子1:
BEGIN
块在任何输入行处理之前运行,打印"Header:"
[root@doc-nginx opt] awk 'BEGIN {print "Users: "} {print $0}' data.txt
Users:
Alice 30 Female
Bob 25 Male
Charlie 35 Male
- 例子2:
END
块在所有行处理完之后运行,打印总行数NR
。
[root@doc-nginx opt] awk '{print $0} END {print "Total users:",NR}' data.txt
Alice 30 Female
Bob 25 Male
Charlie 35 Male
Total users: 3
5.5 组合模式
- 作用:通过逻辑运算符将多个模式组合起来。
- 语法:
(1)
pattern1 && pattern2
:同时满足两个条件。
(2)pattern1 || pattern2
:满足任意一个条件。
(3)!pattern
:取反,匹配不满足条件的行。
- 例子1:匹配包含
"banana"
且第一列值大于10
的行
[root@doc-nginx opt] cat fruit.txt
5 banana
15 orange
10 grape
20 cherry
10 banana
[root@doc-nginx opt] awk '/banana/ && $1 >= 10' fruit.txt
10 banana
- 例子2:匹配包含 “banana” 或 “grape” 的行
[root@doc-nginx opt] cat fruit.txt
5 banana
15 orange
10 grape
20 cherry
10 banana
[root@doc-nginx opt] awk '/banana/ || /grape/' fruit.txt
5 banana
10 grape
10 banana
- 例子3:匹配不包含 “banana” 的行
[root@doc-nginx opt] cat fruit.txt
5 banana
15 orange
10 grape
20 cherry
10 banana
[root@doc-nginx opt] awk '!/banana/' fruit.txt
15 orange
10 grape
20 cherry
6 action
当 模式
匹配成功时,执行与之对应的 action(操作)
。如果没有指定 pattern
,则会对每一行都执行对应的 action
。action
可以包含任意的 awk
语句,包括 输出
、变量
、控制结构(如循环、条件判断)
等。
6.1 使用控制结构(循环、条件语句)
6.1.1 使用 for 循环
awk
中的 for
循环语法与其他编程语言相似。常见的用法包括循环遍历数组或重复执行某个操作。
- 例子:遍历每一个字段并逐个输出
[root@doc-nginx opt] cat fruit.txt
5 banana
15 orange
10 grape
20 cherry
10 banana
[root@doc-nginx opt] awk '{for(i=1; i<=NF; i++) print $i}' fruit.txt
5
banana
15
orange
10
grape
20
cherry
10
banana
6.1.2 使用 while 循环
awk
也支持 while
循环,它在某些情况下可能更方便,尤其是需要基于条件执行某些操作时。
- 例子:遍历每一个字段并逐个输出
[root@doc-nginx opt] cat fruit.txt
5 banana
15 orange
10 grape
20 cherry
10 banana
[root@doc-nginx opt] awk '{i = 1; while(i <= NF) { print $i; i++; }}' fruit.txt
5
banana
15
orange
10
grape
20
cherry
10
banana
6.2 数组的使用
awk
允许使用数组来存储数据。数组的索引可以是任何字符串或数字,数组本身是动态的,不需要预先定义大小。
6.2.1 数组的基本使用
- 例子:将每一行的第一列作为数组的
键(索引)
,第二列作为数组的值
。在END
块中,使用for (key in arr)
遍历数组,输出每个键
和值
。
[root@doc-nginx opt] cat fruit.txt
5 banana
15 orange
10 grape
20 cherry
10 banana
[root@doc-nginx opt] awk '{arr[$2] = $1} END { for (key in arr) {print key, ":", arr[key]} }' fruit.txt
orange : 15
banana : 10
grape : 10
cherry : 20
6.2.2 数组统计
- 例子:使用数组统计每个单词的出现次数
[root@doc-nginx opt] cat >fruit2.txt<<EOF
> apple
> banana
> apple
> orange
> banana
> banana
> grape
> EOF
[root@doc-nginx opt] awk '{count[$1]++} END {for(key in count) print key, ":" , count[key]}' fruit2.txt
orange : 1
apple : 2
banana : 3
grape : 1