目录
一.什么是awk
二.awk的语法格式
1.选项
2. 模式(Pattern)
3. 操作(Action)
4. 输入文件(file)
5.总结
三.awk的工作原理
1. 逐行扫描输入
2. 匹配模式
1.正则表达式:
2.逻辑表达式:
3.特殊模式:
3. 执行操作
打印:
计算:
修改字段:
4. 内置变量
5. 工作流程
四 练习
4.1 awk命令基础部分
4.2awk命令高级部分
一.什么是awk
awk
是一种模式扫描和处理语言,其核心思想是:
- 逐行扫描输入:
awk
会逐行读取输入文件或数据流。 - 匹配模式:通过定义模式(可以是正则表达式或逻辑条件)来匹配特定的行。
- 执行操作:对匹配的行执行指定的操作(如打印、计算、修改等)。
二.awk的语法格式
awk
命令主要由 模式(Pattern) 和 操作(Action) 组成,其基本语法如下:
awk [选项] 'pattern { action }' file
1.选项
-
-F 定义字段分隔符,默认分隔符是空格或制表符
-
-v 定义变量并赋值
-
-f 指定文件里的命令来处理文件
2. 模式(Pattern)
模式用于匹配输入行,决定是否执行操作。模式可以是以下类型:
正则表达式:
- 使用
/pattern/
匹配包含特定模式的行。 - 示例:
awk '/error/ { print }' file.txt # 打印包含 "error" 的行
逻辑表达式:
- 使用比较运算符(如
==
、>
、<
等)匹配满足条件的行。 - 示例:
awk '$1 > 10 { print }' file.txt # 打印第一个字段大于 10 的行
特殊模式:
BEGIN
:在处理输入之前执行的操作。END
:在处理完所有输入后执行的操作。- 示例:
awk 'BEGIN { print "Start" } { print } END { print "End" }' file.txt
空模式:
- 如果模式为空,则默认匹配所有行。
- 示例:
awk '{ print }' file.txt # 打印所有行
3. 操作(Action)
操作是当模式匹配时执行的代码块,用
{}
包围。操作可以是以下内容:
打印:
- 使用
print
或printf
输出内容。 - 示例:
awk '{ print $1 }' file.txt # 打印每行的第一个字段
计算:
- 对字段或变量进行数学运算。
- 示例:
awk '{ sum += $1 } END { print sum }' file.txt # 计算第一列的总和
修改字段:
- 直接修改字段的值。
- 示例
awk '{ $1 = "new_value"; print }' file.txt # 将第一列替换为 "new_value"
4. 输入文件(file)
awk
命令可以处理一个或多个文件。如果未指定文件,则从标准输入读取数据。
5.总结
awk
命令的完整结构:
awk [选项] 'BEGIN { initialization } pattern { action } END { finalization }' file
BEGIN
块:在处理输入之前执行,通常用于初始化变量或打印标题。
END
块:在处理完所有输入后执行,通常用于输出统计结果或总结。
再次强调:awk
命令的结构由 模式 和 操作 组成,支持 BEGIN
和 END
块进行初始化和收尾工作。
三.awk的工作原理
1. 逐行扫描输入
awk 会逐行读取输入文件或数据流(如果没有指定文件,则从标准输入读取)。对于每一行,awk 会执行以下步骤:
- 将当前行存储在内部变量
$0
中。 - 根据字段分隔符(默认是空格或制表符)将行分割为多个字段,分别存储在
$1
、$2
、$3
等变量中。 - 更新内置变量(如
NR
表示当前行号,NF
表示当前行的字段数)。
2. 匹配模式
awk
支持多种模式匹配方式:
1.正则表达式:
-
使用
/pattern/
来匹配包含特定模式的行。 -
示例
awk '/error/ { print }' file.txt # 打印包含 "error" 的行
2.逻辑表达式:
- 使用比较运算符(如
==
、>
、<
等)来匹配满足条件的行。 - 示例:
awk '$1 > 10 { print }' file.txt # 打印第一个字段大于 10 的行
3.特殊模式:
BEGIN
:在处理输入之前执行的操作。END
:在处理完所有输入后执行的操作。- 示例
awk 'BEGIN { print "Start" } { print } END { print "End" }' file.txt
3. 执行操作
当模式匹配时,awk
会执行相应的操作。操作可以是:
打印:
- 使用
print
或printf
输出内容。 - 示例
awk '{ print $1 }' file.txt # 打印每行的第一个字段
计算:
- 对字段或变量进行数学运算。
- 示例:
awk '{ sum += $1 } END { print sum }' file.txt # 计算第一列的总和
修改字段:
- 直接修改字段的值。
- 示例:
awk '{ $1 = "new_value"; print }' file.txt # 将第一列替换为 "new_value"
4. 内置变量
awk
提供了许多内置变量,用于控制和处理数据:
变量 | 描述 |
---|---|
NR | 当前处理的行号(从 1 开始)。 |
NF | 当前行的字段数。 |
FS | 字段分隔符(默认是空格或制表符)。 |
OFS | 输出字段分隔符(默认是空格)。 |
RS | 记录分隔符(默认是换行符)。 |
ORS | 输出记录分隔符(默认是换行符)。 |
FILENAME | 当前处理的文件名 |
$0 | 当前处理的行的整行内容 |
$n | 当前处理行的第n个字段(第n列) |
5. 工作流程
综上:awk
的工作流程可以总结为以下步骤:
- 初始化:
- 执行
BEGIN
块中的操作(如果有)。
- 执行
- 逐行处理:
- 读取每一行,更新内置变量(如
NR
、NF
等)。 - 检查是否匹配模式,如果匹配则执行操作。
- 读取每一行,更新内置变量(如
- 结束处理:
- 执行
END
块中的操作(如果有)。
- 执行
四 练习
4.1 awk命令基础部分
[root@localhost ~]# cat /etc/passwd | head -10 > zz
#以这条命令为前提执行如下命令1.逐条打印zz文件的内容
awk '{print}' zz2.逐条打印zz文件的每一行的第一个字段(默认以空格或制表符分隔)。
awk '{print $1}' zz3.以 : 作为字段分隔符,打印 zz 文件中每一行的第 5 个字段。
awk -F:'{print $1}' /etc/passwd4.以 x 作为字段分隔符,打印 /etc/passwd 文件中每一行的第一个字段。
awk -Fx '{print $1}' /etc/passwd5.打印 zz 文件中每一行的第一个和第二个字段(默认以空格或制表符分隔),并将它们连接在一起。
awk '{print $1 $2}' zz6.打印 zz 文件中每一行的第一个和第二个字段(默认以空格或制表符分隔),并在它们之间插入一个空格。
awk '{print $1" "$2}' zz
或
awk '{print $1,$2}' zz7.打印 zz 文件中每一行的第一个和第二个字段(默认以空格或制表符分隔),用制表符作为分隔符输出。
awk -F: '{print $1"\t"$2}' zz8.打印包含root的整行内容
awk -F: '/root/{print $0}' zz 9.打印包含root的行的第一列
awk -F: '/root/{print $1}' zz10.以:或/作为字段分隔符,计算并输出zz文件中每一行的字段数量
awk -F[:/] '{print NF}' zz11.以:或/作为字段分隔符,逐行处理zz文件,并输出当前行的行号
awk -F[:/] '{print NR}' zz12.打印 /etc/passwd 文件的第二行。
awk 'NR==2' /etc/passwd
或awk 'NR==2{print}' /etc/passwd13.以:为分隔符,打印/etc/passwd文件第二行的第一列。
awk -F: 'NR==2{print $1}' /etc/passwd14. 打印最后一列
awk -F: '{print $NF}' /etc/passwd15.在文件处理结束后,打印文件的总行数。
awk 'END{print NR}' /etc/passwd16.在文件处理结束后,打印文件的最后一行。
awk 'END{print $0}' /etc/passwd17.以:为分隔符,打印/etc/passwd文件的每一行有几列。
awk -F: '{print "第"NR"行有"NF"列"}' /etc/passwd
1.查看本机IP地址
ifconfig ens33 | awk '/netmask/{print "本机的ip地址是"$2}'2.根分区的可用量
df -h | awk 'NR==2{print $4}'3.BEGIN块的一些注意事项:
(1)BEGIN块在处理文件之前执行,因此不需要指定文件名
运行awk 'BEGIN{x=10;print x+1}' 会直接输出结果11
如果没有BEGIN块:运行awk '{x=10; print x+1}' filename ;这条命令会逐行处理filename文件,并对每一行执行 {x=10; print x+1}。(2)不指定初始值,初始值就为0,如果是字符串,则默认为空awk 'BEGIN{print x+1}' 输出为1
小数也可以运算 awk 'BEGIN{print 2.5+3.5}' 输出为6
^和**都是幂运算 awk 'BEGIN{print 2^3}' awk 'BEGIN{print 2**3}' 输出都是84. awk -F: '/root/' /etc/passwd
在awk中,如果省略 print,默认行为是打印整行(即 print $0)。5.用~表示包含,!~表示不包含
注意~和!~是模糊匹配(用于在不完全精确匹配的情况下,找到与目标最相似的结果)例1:awk -F: '$1~/ro/' /etc/passwd
#模糊匹配,只要有ro就匹配上
例2:awk -F: '$7!~/nologin$/{print $1,$7}' /etc/passwd
#从/etc/passwd文件中提取用户的登录名($1)和登录Shell($7),但只选择那些登录Shell不以nologin结尾的行。
内置变量的用法
1.awk 'BEGIN{FS=":";OFS="---"}{print $1,$2}' pass.txt
#OFS定义了输出时以什么分隔,$1$2中间要用逗号分隔,因为逗号默认被映射为OFS变量,而这个变量默认是空格
输出结果为:
root---x
bin---x
daemon---x
adm---x
lp---x2.awk 'BEGIN{RS=":"}{print $0}' /etc/passwd
#RS:指定以什么为换行符,这里指定是冒号,你指定的必须是原文里存在的字符3.awk 'BEGIN{ORS=" "}{print $0}' /etc/passwd
#将/etc/passwd文件中的每一行连接起来,并用空格作为分隔符输出。
4.2awk命令高级部分
awk与if语句结合
例1:简单条件判断
假设有一个文件 data.txt,内容如下:
10
20
30
40
50
要求:如果某行的值大于 30,则打印该行。awk '{if ($1 > 30) print $0}' data.txt
要求:只打印奇数行。 awk '{if (NR % 2 == 1) print $0}' data.txt例2:多条件判断
假设有一个文件 users.txt,内容如下:
Alice 25
Bob 30
Charlie 15
David 40
要求:如果年龄大于 20 且小于 40,则打印用户名。
awk '{if ($2 > 20 && $2 < 40) print $1}' users.txt要求:根据分数打印等级:
大于等于 90:A
大于等于 80:B
大于等于 60:C
其他:Dawk '{if ($2 >= 90) {print $1, "A"} else if ($2 >= 80) {print $1, "B"} else if ($2 >= 60) {print $1, "C"} else {print $1, "D"}
}' scores.txt例3:结合正则表达式
假设有一个文件 emails.txt,内容如下:
alice@example.com
bob@gmail.com
charlie@example.org
david@yahoo.com
要求:如果邮箱地址以 @example.com 结尾,则打印该邮箱。
awk '{if ($0 ~ /@example\.com$/) print $0}' emails.txtawk还支持for循环、while循环、函数、数组等
awk高级用法
1.统计 /etc/passwd 文件中以 /bin/bash 结尾的行数,并输出这些行及其编号,最后输出总行数。
awk 'BEGIN{x=0};/\/bin\/bash$/ {x++;print x,$0};END {print x}' /etc/passwd2.输出/etc/passwd文件第3个字段的值不小于200的行
awk -F ":" '! ($3<200){print} ' /etc/passwd3.从/etc/passwd文件中提取每一行的第3个字段(用户 ID)和第4个字段(组 ID),比较它们的值,输出较大的那个值。
awk -F ":" ' {max=($3>=$4) ?$3:$4; {print max}} ' /etc/passwd注意:($3>=$4) ?$3:$4:这是一个三元运算符,用于比较 $3 和 $4 的值:
如果 $3 大于或等于 $4,则返回 $3。
否则,返回 $4。4.逐行读取 /etc/passwd 文件,并在每一行的前面加上行号(NR),然后输出整行内容。
awk -F ":" '{print NR,$0}' /etc/passwd5.输出以冒号分隔且第7个字段中包含/bash的行的第1个字段
awk -F ":" '$7~"bash"{print $1,47}' /etc/passwd6.从 /etc/passwd 文件中提取第1个字段中包含root且有7个字段的行,并输出该行的第1个字段第2个字段和最后一个字段。
awk -F":"'($1~"root") && (NF==7) {print $1,$2,$NF } ' /etc/passwd7.输出/etc/passwd 文件中第7个字段既不为/bin/bash,也不为/sbin/nologin的所有行
awk -F ":”'($7!="/bin/bash")&&($7!="/sbin/nologin"){print} ' /etc/passwd8.查看当前内存使用百分比
free -m |awk '/Mem:/ {print int($3/($3+$4)*100)"%"}'9.统计使用bash 的用户个数
awk -F: '/bash$/ {print}'passwd | wc -l
或
awk -F: '/bash$/{print | "wc -l"}' /etc/passwd10.查看当前CPU空闲率
top -b -n 1 | grep Cpu | awk -F ',' '{print $4}'| awk '{print $1}'
(-b -n 1表示只需要1次的输出结果)11.从 /var/log/secure 日志文件中提取所有失败的 SSH 登录尝试,并统计每个 IP 地址的失败次数。
awk 'BEGIN {ip[$11]=0}; /Failed password/ {ip[$11]++}; END {for(i in ip) {print i" , "ip[i]}}' /var/log/secure
面试题:
找到10:00 到 11:00 之间的日志
awk '$3 >= "10:00:00" && $3 <= "11:00:00"' /var/log/messages