awk是一种在 Linux 和 Unix 系统中非常强大且常用的文本处理工具
一、awk介绍
awk是一种在 Linux 和 Unix 系统中非常强大且常用的文本处理工具,它的名字来源于其三位创始人 Alfred Aho、Peter Weinberger 和 Brian Kernighan 的姓氏首字母。awk可以对文本文件(或来自标准输入的文本流)按行进行扫描,并根据用户指定的规则来处理文本,比如提取特定字段、进行条件筛选、对文本做格式化输出以及执行一些简单的计算等操作。
二、基本工作原理
awk按照以下的基本流程来处理文本:
读取输入:它从文件或者标准输入获取文本内容,逐行读取这些文本数据。
分割字段:默认情况下,awk以空格或者制表符(Tab)作为分隔符,将每行文本分割成一个个字段(可以自定义分隔符),并将这些字段依次编号,从$1开始,$0表示整行内容。例如有一行文本 “John Doe 25”,$1就是 “John”,$2就是 “Doe”,$3就是 “25”,$0就是 “John Doe 25” 整行内容。
匹配模式(可选):可以设定特定的条件模式,比如某个字段满足特定的值、符合某个正则表达式等情况。只有匹配上这些模式的行,才会执行后续相应的动作。
执行动作:针对匹配模式的行,执行用户定义的操作,例如打印特定字段、进行运算、修改文本内容等,然后输出处理后的结果。
一、基本打印操作
示例 1:打印文件的每一行
假设存在一个名为 test.txt 的文本文件,内容如下:
line1
line2
line3
使用命令 awk '{ print $0 }' test.txt,将会原样输出文件中的每一行内容,效果等同于 cat test.txt。这里的 $0 表示整行内容,这是 awk 中最基本的打印整行的用法。
示例 2:打印文件每行的第一个字段
若有文件 fruits.txt 内容为:
apple 5
banana 3
cherry 2
执行命令 awk '{ print $1 }' fruits.txt,输出结果为:
apple
banana
cherry
此命令提取并打印了每行文本的第一个字段,因为 $1 代表每行按默认分隔符(空格或制表符)分割后的第一个部分。
二、自定义分隔符
示例 3:以逗号为分隔符处理 CSV 文件并打印指定字段
假设有一个名为 data.csv 的 CSV 文件,内容如下:
John,Doe,25
Alice,Smith,30
想要提取每个人的姓氏(即第二个字段,以逗号为分隔符),可以使用命令:
awk -F ',' '{ print $2 }' data.csv
这里通过 -F 选项指定了逗号 , 作为字段分隔符(等同于在 BEGIN 块中设置 FS=","),然后打印每行的第二个字段,输出结果为:
Doe
Smith
三、条件筛选
示例 4:筛选出满足数值条件的行并打印
有一个文件 scores.txt,记录了学生姓名和成绩,内容如下:
Tom 80
Jerry 75
Lucy 85
要筛选出成绩大于等于 80 分的学生记录,可以使用命令:
awk '$2 >= 80 { print $0 }' scores.txt
只有成绩字段(第二个字段,$2)满足大于等于 80 这个条件的行才会被打印出来,输出结果为:
Tom 80
Lucy 85
示例 5:基于正则表达式筛选行并打印
假设有一个日志文件 access.log,里面有很多访问记录,想要筛选出包含 ERROR 字样的行,可以使用命令:
awk '/ERROR/ { print $0 }' access.log
只要行中匹配到 ERROR 这个正则表达式的行就会被打印输出,方便查找错误相关的日志记录。
四、简单计算与统计
示例 6:计算文件中所有数字的总和
若文件 nums.txt 的内容为:
1
2
3
使用命令:
awk '{ sum += $1 } END { print sum }' nums.txt
在处理每一行时,将每行的第一个字段(也就是数字本身)累加到变量 sum 中,最后在 END 块中输出总和的值,此例中输出结果为 6。
示例 7:计算文件中数字的平均值
同样对于包含数字的文件 nums.txt,计算平均值的命令如下:
awk '{ sum += $1; n++ } END { print sum / n }' nums.txt
这里除了用 sum 累加数字外,还用变量 n 记录行数(每处理一行 n 就加 1),最后在 END 块中用总和除以行数得到平均值,输出相应的计算结果。
五、格式化输出
示例 8:设置输出字段分隔符并打印
对于文件 employees.txt,内容为:
John Doe
Alice Smith
想要在输出时将名字和姓氏用 - 隔开,可以使用命令:
awk 'BEGIN { OFS="-" } { print $1, $2 }' employees.txt
通过 BEGIN 块设置输出字段分隔符 OFS 为 -,然后打印每行的两个字段,输出结果为:
John-Doe
Alice-Smith
六、多文件处理
示例 9:同时处理多个文件并打印行号和内容
假设有两个文件 file1.txt 和 file2.txt,内容分别如下:
file1.txt:
line1 of file1
line2 of file1
file2.txt:
line1 of file2
line2 of file2
使用命令:
awk '{ print NR, $0 }' file1.txt file2.txt
awk 会依次处理这两个文件,NR 变量表示行号,会从 1 开始连续计数,输出结果如下:
1 line1 of file1
2 line2 of file1
3 line1 of file2
4 line2 of file2
七、Linux 系统中使用awk工具结合正则表达式的一些日常工作常用命令示例
一、匹配特定开头的文本行
示例 1:匹配以特定字符串开头的行并打印
假设有一个文本文件 fruits.txt,内容如下:
apple is red
banana is yellow
cherry is red
avocado is green
若想筛选出以 a 开头的行,可以使用如下 awk 命令:
awk '/^a/ { print $0 }' fruits.txt
命令中的正则表达式 /^a/ 表示匹配以字母 a 开头的行,其中 ^ 是行首定位符。上述命令的输出结果为:
apple is red
avocado is green
二、匹配特定结尾的文本行
示例 2:匹配以特定字符串结尾的行并打印
同样对于上述 fruits.txt 文件,若要筛选出以 red 结尾的行,可使用命令:
awk '/red$/ { print $0 }' fruits.txt
这里的正则表达式 /red$/ 中,$ 是行尾定位符,整个表达式用于匹配以 red 结尾的行,输出结果为:
apple is red
cherry is red
三、匹配包含特定字符串的文本行
示例 3:匹配包含某一特定单词的行并打印
假设存在文件 log.txt,内容包含一些系统操作日志记录,如下所示:
INFO: Process started successfully
ERROR: File not found
WARN: Disk space is low
INFO: Task completed
若要筛选出包含 INFO 字样的行,使用命令:
awk '/INFO/ { print $0 }' log.txt
只要行中出现 INFO 这个字符串(无论其在什么位置),该行就会被匹配并打印出来,输出结果为:
INFO: Process started successfully
INFO: Task completed
四、匹配包含多个特定字符串之一的文本行(使用 “或” 逻辑)
示例 4:匹配包含多个特定单词中任意一个的行并打印
对于文件 messages.txt,内容如下:
Message type A received
Message type B sent
Message type C processed
想要筛选出包含 A 或者 B 的行,可使用如下 awk 命令,通过 | 符号来表示 “或” 的逻辑关系:
awk '/A|/B/ { print $0 }' messages.txt
输出结果为:
Message type A received
Message type B sent
五、匹配特定字符重复出现的文本行
示例 5:匹配包含连续多个相同字符的行并打印
假设有文件 test.txt,内容如下:
aaa is here
bb is there
cccc appears
若要筛选出包含连续 3 个及以上相同字符的行,可以使用正则表达式 /[a-z]{3,}/,命令如下:
awk '/[a-z]{3,}/ { print $0 }' test.txt
该正则表达式中 [a-z] 表示匹配小写字母,{3,} 表示前面的字符至少连续出现 3 次。上述命令的输出结果为:
aaa is here
cccc appears
六、匹配特定字符范围的文本行
示例 6:匹配包含指定范围内字符的行并打印
对于文件 chars.txt,内容如下:
abcdef
ghijkl
mnopqr
若想筛选出包含 c 到 f 之间字符的行,可使用正则表达式 /[c-f]/,命令如下:
awk '/[c-f]/ { print $0 }' chars.txt
输出结果为:
abcdef
七、使用分组与反向引用(较高级用法)
示例 7:匹配重复出现的单词并打印相关行(利用分组与反向引用)
假设有文件 words.txt,内容如下:
hello hello world
bye bye everyone
nice day
想要筛选出包含连续重复单词的行,可以使用如下命令:
awk '/([a-z]+) \1/ { print $0 }' words.txt
这里的正则表达式中,([a-z]+) 是一个分组,用于匹配一个或多个小写字母组成的单词,\1 是反向引用,表示引用前面第一个分组所匹配的内容,即要求后面跟着与前面分组匹配内容相同的单词。输出结果为:
hello hello world
bye bye everyone