当前位置: 首页 > news >正文

shell编程之awk命令详解

1. awk 教程

1.1 调用 awk

awk 是一种强大的文本处理工具,在 Linux 系统中广泛应用于日志分析、数据处理等场景。调用 awk 主要有以下三种方式:

1.1.1 命令行方式

基本语法为:

awk (-F filed-separator) 'commands' input-files

其中,-F用于指定分隔符,默认情况下,awk 以空格或制表符作为分隔符。commands是 awk 的命令,input-files则是要处理的文件。例如,我们有一个文件data.txt,内容如下:

apple 3 1.5
banana 5 2.0
cherry 2 1.8

如果我们想以空格为分隔符,打印每一行的第一个和第三个字段,可以使用以下命令:

awk '{print $1,$3}' data.txt

输出结果为:

apple 1.5
banana 2.0
cherry 1.8

如果文件中的字段是以冒号分隔,我们就需要使用-F选项指定分隔符。比如有一个users.txt文件,内容为:

user1:password1:1001
user2:password2:1002
user3:password3:1003

要打印每个用户的用户名(第一个字段)和用户 ID(第三个字段),命令如下:

awk -F: '{print $1,$3}' users.txt

输出:

user1 1001
user2 1002
user3 1003

注意:

 单引号双引号都行,但是要按照规范

场景单引号(')双引号(")
纯正则匹配推荐使用,语法简洁,避免 Shell 干扰也可使用,但需注意转义
包含 Shell 变量无法直接使用,需额外处理直接引用变量,Shell 先解析
正则包含特殊字符自动防止 Shell 解析,直接使用需用反斜杠转义(如\$\+
避免引号嵌套错误适合正则中无单引号的场景适合正则中包含单引号的场景

1.1.2 脚本文件可执行方式

将所有 awk 命令插入一个文件,并使该文件可执行。同时,在脚本文件的首行使用#!/usr/bin/awk -f,这样就可以通过直接键入脚本名称来调用它。
例如,创建一个名为process.awk的文件,内容如下:

#!/bin/awk -f
{print $2}

然后为该文件添加可执行权限:

chmod +x process.awk

假设有一个input.txt文件,内容为:

one two three
four five six
seven eight nine

执行process.awk脚本处理input.txt文件:

./process.awk input.txt

输出结果为:

two
five
eight

如果想要改变分隔符:

#!/bin/awk -f
# 设置字段分隔符为冒号
BEGIN { FS = ":" }   #FS 的英文全称是Field Separator
{ print $1, $3 }

1.1.3 调用外部脚本方式

将所有的 awk 命令插入一个单独文件,然后使用-f选项调用该脚本。语法为:

awk -f awk-script-file input-files

例如,有一个脚本文件calculate.awk,内容如下:

{
sum = $1 + $2
print sum
}

我们有一个数据文件numbers.txt,内容为:

3 5
2 7
4 6

执行命令:

awk -f calculate.awk numbers.txt

输出:

8
9
10

1.2 awk 脚本

1.2.1 模式和动作

任何 awk 语句都由模式和动作组成。模式部分决定动作语句何时触发及触发条件,而动作则是对数据进行的具体操作。如果省略模式部分,动作将对每一行输入数据都执行。
模式可以是条件语句、复合语句或正则表达式,其中有两个特殊字段BEGINENDBEGIN语句用于设置计数、打印表头之类的操作,它会在任何文本浏览动作之前执行。END语句则在 awk 完成对所有输入文本的浏览动作后执行,通常用于打印输出文本总数、结尾状态标志等。
动作通常放在大括号{}内。动作最常见的是打印操作,但也可以包含更长的代码,如if语句、循环语句及循环退出结构等。如果不指明动作,awk 将默认打印出所有输入记录。
例如,我们要处理一个成绩文件grades.txt,内容如下:

Alice 85 90 78
Bob 70 65 80
Charlie 95 88 92

我们想在处理文件前打印表头,处理文件时打印每个学生的姓名和平均成绩,处理完后打印一个结束信息。可以使用以下 awk 脚本:

awk

BEGIN {
print "Student\tAverage Grade"
print "----------------------"
}
{
avg = ($2 + $3 + $4) / 3
print $1 "\t" avg
}
END {
print "----------------------"
print "End of Grades Report"
}

执行该脚本:

awk -f script.awk grades.txtsource files / command-line arguments must contain complete functions or rules
出现这个错误可能是你的大括号未闭合

输出:

Student Average Grade
----------------------
Alice 84.3333
Bob 71.6667
Charlie 91.6667
----------------------
End of Grades Report

1.2.2 域和记录

awk 执行时,会将输入的每一行视为一条记录,并且将记录中的各个部分(以分隔符分隔)标记为$1$2……$n,这种方式称为域标识。当需要指定多个域时,使用逗号,进行分隔,如$1,$3指定的是第一个域和第三个域。如果希望指定整行记录,则可以使用$0
使用print命令执行打印操作,该命令需要用{}括起来。

1.2.2.1 抽取域

以之前的grades.txt文件为例,我们要打印每个学生的姓名(第一个域)和数学成绩(第二个域),命令如下:

awk '{print $1,$2}' grades.txt

输出:

Alice 85
Bob 70
Charlie 95
1.2.2.2 保存 awk 输出

保存 awk 输出结果主要有两种方式:

  • 重定向到文件:这种方式下,屏幕不会显示输出内容,而是将结果保存到指定文件中。例如,将grades.txt文件中每个学生的姓名保存到students.txt文件中,命令为:

awk '{print $1}' grades.txt > students.txt

  • 使用管道将输出结果传给teetee命令可以将输出同时显示在屏幕上并保存到文件中。例如,将grades.txt文件中每个学生的总成绩(三个成绩之和)输出到屏幕并保存到total_grades.txt文件中,命令如下:
awk '{sum=$2+$3+$4; print sum}' grades.txt | tee total_grades.txttee命令不可用的话,下载
yum install coreutils
1.2.2.3 使用标准输入

可以通过多种方法将标准输入作为 awk 的输入源:

  • 直接在命令后跟上文件名,如awk '{print $0}' grades.txt,这里grades.txt的内容会作为标准输入被 awk 读取处理。
  • 使用<符号指定输入文件,如awk '{print $0}' < grades.txt,效果与上一种方法相同。
1.2.2.4 打印所有记录

要打印输入文件的所有记录,使用以下命令:

awk '{print $0}' input_file

其中input_file是要处理的文件名。

1.2.2.5 打印单独记录

只打印特定的域,如之前提到的只打印$1$4

awk '{print $1,$4}' input_file
1.2.2.6 自定义格式打印

我们可以在输出内容中添加注释、自定义分隔符等。例如,对于grades.txt文件,我们要在输出学生姓名和平均成绩时,在上方添加注释 “Student Name” 和 “Average Score”,并使用制表符分隔,命令如下:

awk 'BEGIN {print "Student Name\tAverage Score\n------------------------------"} {avg = ($2 + $3 + $4) / 3; print $1 "\t" avg}' grades.txt

输出:

Student Name Average Score
------------------------------
Alice 84.3333
Bob 71.6667
Charlie 91.6667
1.2.2.7 awk 错误信息提示

在使用 awk 时,如果遇到错误,可以从以下几个方面排查:

  • 确保整个 awk 命令用单引号括起来,因为双引号在 Shell 中可能会导致变量提前展开等问题,影响 awk 命令的执行。
  • 确保命令内所有引号成对出现,无论是单引号还是双引号。
  • 确保用大括号{}括起动作语句,用括号()括起条件语句。
  • 检查是否遗漏了大括号{},尤其是在包含多个动作或复杂条件判断时。
1.2.2.8 awk 键盘输入

如果在执行 awk 命令时没有指定输入文件,awk 会从键盘读取输入。输入完成后,按Ctrl + D组合键结束输入。例如,执行awk '{print $0}',然后在命令行输入一些文本,每输入一行按回车键,输入完成后按Ctrl + D,awk 会打印出你输入的每一行内容。

1.2.3 元字符

awk 支持一些元字符,用于模式匹配等操作,常见的元字符有\^$.()|*+?。其中+?在 grep 或 sed 中可能有不同的行为,但在 awk 中有其特定的含义:

  • +:匹配一个或一个以上前面的单字符。例如,/XY+Z/可以匹配XYZXYYYYZ等。
  • ?:匹配 0 个或一个前面的单字符。例如,/XY?Z/可以匹配XYZXZ
    例如,有一个文件strings.txt,内容为:
XZY
XYZY
XYYYYZY
XZ

要匹配包含XY后面跟着一个或多个Y再跟着Z的字符串,可以使用以下命令:

awk '/XY+Z/' strings.txt

输出:

XYZY
XYYYYZY
[root@free ~]# awk '/XY?Z/' string.txt 
XZY
XYZY
XZ

1.2.4 条件操作符

awk 支持多种条件操作符,用于条件判断:

操作符描述
<小于
<=小于等于
==等于
!=不等于
>大于
>=大于等于
~匹配正则表达式
!~不匹配正则表达式
1.2.4.1 匹配

使用~紧跟正则表达式可以匹配域,也可以使用if语句进行条件判断,条件需要用()括起来。
例如,有一个文件employees.txt,内容如下:

John,Manager,50000
Alice,Engineer,45000
Bob,Engineer,48000

要查询职位是工程师(Engineer)的员工信息(打印出$2匹配Engineer的行),可以使用以下两种方式:

awk '{if ($2~/Engineer/) print $0}' employees.txt为什么不需要分号?
因为 if 语句控制下的 print 是同一个逻辑块的一部分,不是独立的语句。正则表达式的基本语法:
在 awk 中,正则表达式通常用 /pattern/ 表示,其中:
开头的 /:标记正则表达式的开始;
结尾的 /:标记正则表达式的结束;
中间的 pattern:是具体的匹配模式(如 Engineer)。

或者

awk '$2 ~ /Engineer/' employees.txt
1.2.4.2 精确匹配

使用==并用双引号括起条件可以进行精确匹配。例如,要查询薪资为48000的员工信息:

awk '{if ($3 == "48000") print $0}' employees.txt
1.2.4.3 不匹配

使用!~紧跟正则表达式可以实现不匹配域的操作。例如,要查询职位不是经理(Manager)的员工信息:

awk '{if ($2!~/Manager/) print $0}' employees.txt

或者

awk '$2 !~ /Manager/' employees.txt
1.2.4.4 比较

以比较薪资大小为例,要找出薪资大于45000的员工姓名和薪资:

awk '{if ($3 > 45000) print $1,$3}' employees.txt
1.2.4.5 各种匹配
  • 匹配Greengreen

awk '/(G|g)reen/' input_file

  • 匹配$1的第四个字符是a

awk '$1 ~ /^...a/' input_file

  • 匹配YellowBrown

awk '$4 ~ /Yellow|Brown/' input_file

  • 匹配以J开头的行:

awk '$0 ~ /^J/' input_file
1.2.4.6 复合表达式

复合模式或复合操作符用于形成复杂的逻辑操作,复合表达式即为模式间通过使用复合操作符互相结合起来的表达式。常用的复合操作符有&&(逻辑与)和||(逻辑或):

  • &&(AND):符号两边的条件必须同时为真。例如,要查询职位是工程师且薪资大于45000的员工信息:

awk '{if ($2 == "Engineer" && $3 > 45000) print $0}' employees.txt

  • ||(OR):符号两边的条件只要有一个为真即可。例如,要查询职位是经理或者薪资大于48000的员工信息:

awk '{if ($2 == "Manager" || $3 > 48000) print $0}' employees.txt

1.2.5 awk 内置变量

awk 有许多内置变量,用于设置环境信息、获取输入输出相关的状态等。以下是一些常用的内置变量:

  • ARGC:表示命令行参数的个数。例如,执行awk -v var1=value1 -v var2=value2 -f script.awk file1 file2ARGC的值为5(包括awk命令本身、两个-v选项及两个文件名)。
  • ARGV:是一个数组,存储命令行参数的排列。ARGV[0]通常是awk命令本身,ARGV[1]及后续元素为命令行参数。
  • FNR:与NR类似,用于记录输入的行数。不同之处在于,FNR在处理多个文件时,对每个文件都会从1开始计数,而NR是对所有输入文件的总行数进行计数。例如,有两个文件file1.txtfile2.txt,在处理file1.txt时,FNRNR1开始递增,当处理完file1.txt开始处理file2.txt时,NR继续递增,而FNR又从1开始。
  • FS:用于指定输入字段的分隔符。可以在BEGIN块中定义,也可以使用-F选项在命令行指定。例如,BEGIN {FS=":"}将输入字段分隔符设置为冒号。
  • RS:输入的记录分隔符,默认是换行符,即文本按一行一行输入。可以修改这个变量来改变记录的分隔方式。例如,BEGIN {RS="\n\n"}可以将连续两个换行符作为记录分隔符,适用于处理段落等以空行分隔的文本。
  • OFS:输出字段分隔符,默认是空格。可以修改为其他字符,如制表符\t或逗号等。例如,BEGIN {OFS="|"}会将输出的字段用竖线分隔。
  • ORS:输出的记录分隔符,默认为换行符,即处理结果也是一行一行输出到屏幕。可以修改为其他字符,如BEGIN {ORS=","}会将输出的记录用逗号分隔,最后一个记录后也会有逗号。
    例如,我们要统计一个文件中每行的字段数,并输出行号、每行内容及字段数,使用以下脚本:

{
print NR, $0, NF
}

这里NR表示行号,NF表示当前行的字段数。假设文件example.txt内容为:

apple banana cherry
dog cat mouse

执行awk '{print NR, $0, NF}' example.txt,输出:

1 apple banana cherry 3
2 dog cat mouse 3

再如,我们想以冒号为输入分隔符,以逗号为输出分隔符,打印文件data.csv的第一和第三个字段:

BEGIN {
FS=":"
OFS=","
}
{
print $1,$3
}

假设data.csv内容为:

1:apple:red
2:banana:yellow
3:grape:purple

执行该脚本,输出:

1,red
2,yellow
3,purple

http://www.dtcms.com/a/266333.html

相关文章:

  • 【CHNS】预后/随访 记录
  • 京东和蚂蚁集团寻求人民币稳定币的批准
  • Mac软件打开提示:已损坏,无法打开。您应该将它移到废纸娄 怎么解决?
  • 全星 QMS:制造业全面质量管理的数字化全能平台
  • 【1】确认安装 Node.js 和 npm版本号
  • vue create 和npm init 创建项目对比
  • OneCode图生代码技术深度解析:从可视化设计到注解驱动实现的全链路架构
  • 【效率提升教程】飞书自动化上传图片和文字
  • oltp系统中的数据库的设计严格遵守第三范式,具体怎么理解呢
  • 建设工程长期停工,停工损失如何计算,谁来承担。
  • 【JAVA】类和对象(一)
  • 实战精准压缩打包,通过 Sharp4ArchiveZip过滤指定支持目录与文件类型
  • 蚁群算法的原理及实现示例
  • 【C++详解】STL-list使用(三大特性之一封装详解、cpu高速缓存命中率)
  • 时序数据库TDEngine安装和使用
  • Docker拉取bladex 、 sentinel-dashboard
  • 永洪科技荣获商业智能品牌影响力奖,全力打造”AI+决策”引擎
  • Echarts3D柱状图-圆柱体-文字在柱体上垂直显示的实现方法
  • Spring Boot + 本地部署大模型实现:优化与性能提升
  • js请求避免缓存的三种方式
  • LiteHub中间件之限流实现
  • AI+Web3:从Web2到Web3的范式革命与深度技术实践
  • 智能电动汽车 --- 车辆网关路由缓存
  • 【烧脑算法】最小字典序:巧用单调栈,从栈底到最优解
  • 缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级
  • Oracle如何使用序列 Oracle序列使用教程
  • 【牛客算法】小红的子序列逆序对
  • java类加载机制:Tomcat的类加载机制
  • 歌词引擎·FreeFlow
  • 【深度解析】Seedance 1.0:重新定义 AI 视频生成的工业级标准