1. 命令介绍
awk,
全称是 "Aho, Weinberger, and Kernighan",这是其三位创始人 Alfred Aho、Peter Weinberger 和 Brian Kernighan 的姓氏的首字母组合而成。 是一种强大的文本处理工具,它可以用来处理结构化的文本数据,通常用于从文件或数据流中抽取信息、转换数据格式、计算统计信息等任务。
主要功能
文本处理:awk
可以轻松处理包含字段的文本文件,并支持按字段分割、搜索、替换等操作。
数据抽取:可以从结构化数据中抽取特定字段或行,用于生成报告、提取关键信息等。
格式化输出:awk
可以根据用户定义的格式输出数据,比如添加分隔符、对齐字段等。
数据转换:可以根据用户定义的规则对数据进行转换,比如进行数学运算、日期格式转换等。
条件处理:支持基于条件的处理,比如根据特定条件过滤数据、执行不同的操作等。
自定义函数:可以编写自定义函数来扩展 awk
的功能,以满足特定的需求。
2. 基本用法
awk [options] 'pattern { action }' file
pattern
是一个模式,用于匹配输入数据的行。
{ action }
是一个动作块,用于指定对匹配的行执行的操作。
file
是要搜索的文件名列表。如果未提供文件名,则从标准输入读取输入。
参数
-v, --assign=<变量=值>:设置一个 AWK 变量的初始值。
-b, --bignum=<字数>:设置大数的字数。
-c, --characters-as-bytes:将字符视为字节。
-C, --traditional:将 AWK 设置为传统模式。
-d, --debug:打印调试信息。
-D, --debugger:启动调试器。
-e, --exec=<程序文本>:执行 AWK 程序文本。
-E, --expression=<程序文本>:指定 AWK 表达式。
-f, --file=<脚本文件>:指定包含 AWK 脚本的文件名。
-F, --field-separator=<字段分隔符>:设置字段分隔符。
-h, --help:显示帮助信息。
-i, --lint:启用 lint 模式。
-M, --lint-old:使用旧的 lint 模式。
-N, --lint-old-internal:使用旧的内部 lint 模式。
-n, --no-optimize:禁用优化。
-r, --re-interval:支持间隔正则表达式。
-T, --sandbox:使用沙盒模式执行程序。
-V, --version:显示版本信息。
-W, --source=<程序文本>:指定 AWK 程序文本。
--use-lc-numeric:使用本地化数字格式。
pattern
BEGIN:在处理输入之前只执行一次的模式。
END:在处理输入之后只执行一次的模式。
条件表达式:可以是任何返回真或假值的表达式。如果表达式为真,则执行相应的操作。
模式1, 模式2:当同时匹配模式1和模式2时执行的操作。这相当于逻辑与。
模式1 || 模式2:当匹配模式1或模式2时执行的操作。这相当于逻辑或。
/正则表达式/:当输入行匹配指定的正则表达式时执行的操作。
模式1 && 模式2:当同时匹配模式1和模式2时执行的操作。这相当于逻辑与。
! 模式:当输入行不匹配指定的模式时执行的操作。这相当于逻辑非。
模式
NR: 当前处理的行号(Number of Record)。
FNR: 当前文件的行号(File Number of Record)。
NF: 当前行中的字段数量(Number of Fields)。
/^pattern/: 行以指定的正则表达式 pattern
开头。
/pattern/: 行中包含指定的正则表达式 pattern
。
$1, $2, ..., $n: 当前行的第 1, 2, ..., n 个字段。
length($0): 当前行的字符长度。
/pattern1/, /pattern2/: 从匹配 pattern1
的行到匹配 pattern2
的行之间的所有行。
!pattern: 当行不匹配指定的正则表达式 pattern
时。
(expression): 满足指定表达式的行。
action
action 允许你对匹配到的行执行各种操作,例如打印、计算、赋值、控制流程等。可以根据具体需求组合这些 action 来实现所需的功能。
{ action }:在没有指定 pattern 的情况下执行的默认操作,即对每一行都执行。
{ print }:打印当前输入行。
{ print expr }:打印表达式 expr 的值。
{ printf format, expr1, expr2, ... }:使用指定格式打印表达式的值。
{ variable = expr }:将表达式的值赋给变量。
{ action1; action2 }:按顺序执行多个操作。
{ next }:跳过当前行,继续处理下一行。
{ nextfile }:跳过当前文件,开始处理下一个文件。
{ exit }:立即退出 AWK 程序。
{ exit expr }:根据表达式的值决定是否退出 AWK 程序。
{ delete array[index] }:删除数组中指定索引的元素。
{ next }:跳过当前行,继续处理下一行。
{ nextfile }:跳过当前文件,开始处理下一个文件。
{ continue }:继续处理下一行。
{ break }:跳出当前循环。
{ close(file) }:关闭文件。
3. 示例
1. 打印文件内容:
awk '{print}' file.txt
2. 指定字段分隔符并打印特定字段:
awk -F':' '{print $1, $3}' /etc/passwd
3. 计算文件中数字的总和:
awk '{ sum += $1 } END {print sum}' numbers.txt
4. 查找包含特定关键词的行:
awk '/keyword/' file.txt
5. 使用 BEGIN 和 END 执行初始化和收尾操作:
awk 'BEGIN {print "Start processing..."} {print $0} END {print "Processing finished."}' file.txt
6. 根据条件打印特定行:
awk '$3 > 50 {print $0}' data.txt
7. 在条件满足时进行操作:
awk '$1 == "John" {print "Found John:", $0}' names.txt
8. 计算文件中特定列的平均值:
awk '{ sum += $2; count++ } END {print "Average:", sum/count}' data.txt
9. 删除文件中的空行:
awk NF file.txt
这个命令使用了 AWK 中的一个特殊的模式 - NF
,它用于匹配非空字段的行。NF
是一个内置的 AWK 变量,它存储了当前行中的字段数量(即非空字段的数量)。
对于文件 file.txt
中的每一行,如果该行包含一个或多个非空字段,则打印该行。换句话说,它会删除文件中的空行,因为在 AWK 中,空行被视为没有字段的行,所以它们不会匹配 NF
模式。
10. 处理多个文件并打印文件名:
awk '{print "File:", FILENAME, "Line:", NR, "Content:", $0}' file1.txt file2.txt
11. 计算文件中行数:
awk 'END {print NR}' file.txt
12. 查找并打印文件中最长的行:
awk 'length > max_length { max_length = length; longest_line = $0 } END {print longest_line}' file.txt
13. 打印文件中特定范围的行(例如,打印第 5 行到第 10 行):
awk 'NR >= 5 && NR <= 10 {print}' file.txt
14. 将文件中所有大写字母转换为小写字母:
awk '{print tolower($0)}' file.txt
15. 查找文件中重复的行并打印出来:
awk '{seen[$0]++} END {for (line in seen) if (seen[line] > 1) print line}' file.txt
16. 删除文件中的重复行:
awk '!seen[$0]++' file.txt
17. 按列对文件进行排序(例如,按第二列的数值大小升序排序):
awk '{print $0 | "sort -k2n"}' file.txt
18. 将文件中的制表符转换为空格:
awk '{gsub(/\t/, " "); print}' file.txt
19. 统计文件中每个单词的出现次数:
awk '{for(i=1; i<=NF; i++) words[$i]++} END {for(w in words) print w, words[w]}' file.txt
4. 实际应用
统计分析日志文件
在实际工作中,AWK 可以用于各种文本处理任务,其中一个妙用是日志分析。假设你有一个 Web 服务器的访问日志文件,你可以使用 AWK 来提取有用的信息、进行统计分析、或者过滤特定的数据:
假设日志文件格式如下:
192.168.1.1 - - [10/Jan/2024:13:55:36 +0000] "GET /page1 HTTP/1.1" 200 1343
192.168.1.2 - - [10/Jan/2024:13:56:20 +0000] "GET /page2 HTTP/1.1" 404 456
192.168.1.3 - - [10/Jan/2024:13:57:05 +0000] "POST /submit HTTP/1.1" 200 765
1. 提取访问量最高的页面
awk '{print $7}' access.log | sort | uniq -c | sort -nr | head -n 1
这个命令提取了日志文件中的页面路径,然后使用 sort
、uniq -c
、sort -nr
来对页面路径进行计数并按访问量降序排序,最后使用 head -n 1
获取访问量最高的页面。
sort
:对 awk 输出的页面路径进行排序。
uniq -c
:统计页面路径的出现次数,并输出带有计数的唯一页面路径。-c
选项会将连续的相同行统计成一行,并在行首显示该行出现的次数。
sort -nr
:按照计数值(出现次数)进行降序排序, -n
表示按照数值排序, -r
表示逆序排列。
head -n 1
:取排序后的结果的第一行,即访问量最高的页面路径。
2. 统计访问量最多的 IP 地址
awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -n 1
这个命令提取了日志文件中的 IP 地址,然后使用 sort
、uniq -c
、sort -nr
来对 IP 地址进行计数并按访问量降序排序,最后使用 head -n 1
获取访问量最多的 IP 地址。
3. 计算每分钟的平均访问量
awk '{print substr($4, 14, 5)}' access.log | sort | uniq -c
这个命令提取了日志文件中的时间戳,并截取了分钟部分,然后使用 sort
、uniq -c
对每分钟的访问量进行统计。
处理 CSV 文件
CSV(逗号分隔值)文件是一种常见的数据格式,经常用于存储表格数据。AWK 可以帮助你对 CSV 文件进行各种操作,例如提取特定字段、计算数据、过滤行等。
假设你有一个包含以下内容的 CSV 文件 data.csv
:
Name,Age,City
John,30,New York
Alice,25,Los Angeles
Bob,35,Chicago
1. 提取特定字段
awk -F ',' '{print $1, $3}' data.csv
这个命令会提取 CSV 文件中的第一列和第三列,并将它们打印出来。-F ','
选项指定字段分隔符为逗号。
2. 计算数据
awk -F ',' '{total += $2} END {print "Total Age:", total}' data.csv
这个命令会计算 CSV 文件中第二列的数据总和,并在处理完所有行后打印出来。
3. 过滤行
awk -F ',' '$2 > 25 {print $0}' data.csv
这个命令会打印出 CSV 文件中第二列大于 25 的行。
4. 添加新列
awk -F ',' '{print $0, "Gender: Male"}' data.csv
这个命令会在每一行的末尾添加一个新的列,内容为 "Gender: Male"。
文件内容处理和转换
一个实用的例子是将 grep
和 sed
与 awk
结合起来进行文件内容的处理和转换。假设你有一个文本文件 data.txt
,其中包含了一些文本,你想要查找包含特定关键字的行,并且对这些行进行一些修改。
例如,假设 data.txt
的内容如下:
This is line 1.
This is line 2 with keyword1.
This is line 3 with keyword2.
This is line 4 with keyword1 and keyword2.
This is line 5.
查找包含关键字 keyword1
的行,并且在这些行的末尾添加一个新的文本:
grep 'keyword1' data.txt | sed 's/$/ - Added text/' | awk '{print $0}'
grep 'keyword1' data.txt
:使用 grep
查找包含关键字 keyword1
的行,并将结果输出到标准输出。
sed 's/$/ - Added text/'
:使用 sed
将每行的末尾($
)替换为 - Added text
,即在每一行的末尾添加了新文本。
awk '{print $0}'
:使用 awk
读取 sed
的输出,并将每行原封不动地打印出来。
最终的输出将是这些包含关键字 keyword1
的行,并且在每一行末尾添加了新文本 - Added text
的内容:
This is line 2 with keyword1. - Added text
This is line 4 with keyword1 and keyword2. - Added text