【Linux】awk命令学习

最近用的比较多,学习总结一下。
文档地址:https://www.gnu.org/software/gawk/manual/gawk.html

  • 一、awk介绍
  • 二、语句结构
    • 1.条件控制语句
      • 1)if
      • 2)for
      • 3)while
      • 4)break&continue&next&exit
    • 2.比较运算符
    • 3.逻辑运算符
  • 三、常用内置变量
    • 1.$0 & $n
    • 2.NR & FNR
    • 3.FS & OFS
    • 4.NF
    • 5.ARGIND
  • 四、真实业务场景下的一些demo
    • 1.A&B两文件之间做diff,筛选出B中存在A中不存在的行
    • 2.修改文件中字段间的分隔符
  • 五、相关面试题
    • 1.词频统计
      • PS

一、awk介绍

awk是一个文本编辑器,按照指定的记录分隔符和字段分割符将文件分行分字段,然后一行一行的流式处理数据。

二、语句结构

该命令的一般格式为:awk 'BEGIN{动作} 条件类型1{动作1} 条件类型2{动作2} ... END{动作}' filename

BEGIN中的动作最先执行,一般用来对处理过程的参数如分隔符等进行设置,然后每条数据都依次会根据匹配到的条件类型执行相应的动作,当所有的数据都被处理完成,END中的动作最后执行。BEGIN和END部分都可以省略。

动作中可以是简单的单语句操作,也可以是复杂的多语句操作,像for循环、while循环等,总之,可以像python和java等高级语言那样自由的编写代码。

几个注意的点:

1)整个命令必须用单引号''包裹。如果命令体太长需要分行写,则前一个'必须在第一行,后一个'必须在最后一行,也就是在后一个'的所在行必须结束整个命令。
2)动作语句单语句可以不使用花括号{}包裹,复合语句需要使用花括号{}包裹。
3)条件语句中可以使用小括号()改变计算的优先级。
4)如果命令中需要引号引用字面量,需要使用双引号""
5)每一行记录匹配一个条件类型后,其余的条件类型也会继续匹配,能匹配几个条件类型,就会执行几个对应的动作。
6)如果省略条件类型,也就是对应的动作一定执行,则动作语句必须使用花括号{}包裹,否则报语法错误。
7)动作语句省略时,默认{print $0}

1.条件控制语句

具体参考https://www.gnu.org/software/gawk/manual/gawk.html#Control-Statements-in-Actions,这里只列举部分常用示例。

1)if

语句格式:if (condition) then-body [else else-body]
如果else关键字和then-body语句处在同一行 且 then-body不是复合语句,也就是没有使用花括号{}包裹,那么elsethen-body之间必须使用分号;隔开,否则报语法错误。

[wdy@node1 ~]$ cat test1
A B C
D E F
G H# 这种情况必须带分号
[wdy@node1 ~]$ cat test1 | awk '{if(NF>=3) print ">=3";else print "<3"}'
>=3
>=3
<3# then-body被{}包裹可以去分号
[wdy@node1 ~]$ cat test1 | awk '{if(NF>=3){print ">=3"}else print "<3"}'
>=3
>=3
<3

2)for

语句格式:for (initialization; condition; increment) body

[wdy@node1 ~]$ cat test1 | awk '{for(i=1;i<=NF;i++) print $i}'
A
B
C
D
E
F
G
H

3)while

语句格式:while (condition) body

[wdy@node1 ~]$ cat test1 | awk '{i=1;while(i<=NF) {print $i;i++}}'
A
B
C
D
E
F
G
H

4)break&continue&next&exit

这几个都是循环体中的关键字,主要对比下作用上的区别:

  • break:直接结束当前整个循环体。
  • continue:跳过本次循环循环体之后的语句,直接进入下一次循环。
  • next:跳过当前行。这个关键字和continue容易混淆,看起来作用好像差不多,区别在于所结束的“循环对象”不同。awk中数据是一行行读入的,这本身就可以看成是一个循环;而一般我们自己定义的循环,是从列或其他维度循环,因此如果我们定义的循环维度不是从行的维度,那么next是直接结束当前行相关的任何操作跳到下一行。而continue在跳过循环体之后的语句后会继续执行与当前行相关的操作。所以我觉得理解这两个关键字的区别从循环的维度是行还是列可能更好理解一些。
  • exit:如果有END语句,则直接执行END中的动作再结束awk命令,如果没有END语句,则直接结束命令。
# break
[wdy@node1 ~]$ cat test1 | awk '{
> for(i=1;i<=NF;i++){
> if($i=="A") break;print $i}}'
D
E
F
G
H# continue
[wdy@node1 ~]$ cat test1 | awk '{
> for(i=1;i<=NF;i++){
> if($i=="A") continue;print $i}}'
B
C
D
E
F
G
H# next
[wdy@node1 ~]$  cat test1 | awk '{
> for(i=1;i<=NF;i++){
> if($i=="B") next;print $i}}'
A
D
E
F
G
H# exit
[wdy@node1 ~]$ cat test1 | awk '{
> for(i=1;i<=NF;i++){
> if($i=="B") exit;print $i}}
> END{print "finish"}'
A
finish

2.比较运算符

文档:https://www.gnu.org/software/gawk/manual/gawk.html#Comparison-Operators
在这里插入图片描述

3.逻辑运算符

!:not,取反
&&:and
||:or

三、常用内置变量

1.$0 & $n

$0表示当前行这整个记录,$n表示当前行的第n个字段。

[wdy@node1 ~]$ cat test1 
A B C
D E F
G H[wdy@node1 ~]$ cat test1 | awk '{print $0}'
A B C
D E F
G H[wdy@node1 ~]$ cat test1 | awk '{print $1}'
A
D
G

2.NR & FNR

Number of Records & File Number of Records,都用来对文件的当前行计数,从1开始。也就是说第一行的数据,NR=1,第二行的数据,NR=2,…,依次类推。区别在于,FNR只在每个文件内累计,跨文件时重新从1开始计数。NR在整个命令执行期间跨文件计数,相当于记录了整个流式处理过程中到当前为止累计处理的行数。

[wdy@node1 ~]$ awk '{print NR,$0}' test1 test1 
1 A B C
2 D E F
3 G H
4 A B C
5 D E F
6 G H[wdy@node1 ~]$ awk '{print FNR,$0}' test1 test1 
1 A B C
2 D E F
3 G H
1 A B C
2 D E F
3 G H

3.FS & OFS

Field Separator & Output Field Separator,默认值都是空格。这两个变量都是用来指定字段分隔符。FS指定读数据时的字段分隔符,OFS指定输出数据时的字段分隔符。

# 读取输入流时空格分隔,输出流制表符\t分隔
[wdy@node1 ~]$ awk 'BEGIN{FS=" ";OFS="\t"}{print $1,$2}' test1 
A       B
D       E
G       H

这里有几个需要注意的点:
1)指定FS时,如果文件中的字段分隔符为\t,而FS指定的是空格,那么么文件会被正常划分字段赋值给$n这样子的。如果文件中的分割符是空格,而指定的FS是\t,那么每行数据之间不会被分割,也就是一行同时也是一个字段。可以这么来理解:\t其实也是一种特殊的空白字符,一般包含4个空格。实际\tFS空格,则awk会正常按照空格分隔并忽略多余的空格。实际空格FS\t时,在文本中不能找到\t所对应的空格长度,也就是找不到指定的分隔符,所以一整行数据就会被划分为一个字段了。

[wdy@node1 ~]$ awk 'BEGIN{FS=" "}{print $1}' test1 
A
D
G[wdy@node1 ~]$ awk 'BEGIN{FS="\t"}{print $1}' test1 
A B C
D E F
G H

2)print后面的变量之间只有以,隔开时指定的OFS才会生效,以,分隔时会将默认值空格替换为指定的OFS插在输出变量之间。
3)如果输出的变量是$0即整行数据,想对这整行重新使用指定的OFS分隔输出,直接print $0并不会改变输出记录的原有分隔符。因为就像上面说到的那样,以,分隔时会将默认值空格替换为指定的OFS插在输出变量之间,$0本身只是一个变量而已,如果有这种需求,可以通过下面的这种技巧实现:

# 可以看到输出时并没有将分割符重新转为\t
[wdy@node1 ~]$ awk 'BEGIN{FS=" ";OFS="\t"}{print $0}' test1 
A B C
D E F
G H# 使用下面这种技巧实现转换
[wdy@node1 ~]$ awk 'BEGIN{FS=" ";OFS="\t"} $1=$1{print $0}' test1 
A       B       C
D       E       F
G       H

可以这么理解下面这种重新赋值的技巧原理:如果不重新赋值,$0只是记录了一个原始数据行的变量而已,即使输出$1、$2等,awk只会根据FS对$0进行分割,输出时变量之间再按照指定的OFS分隔输出。但是这并不会影响原来$0的值。如果使用了$1=$1这种重新赋值的技巧,awk会将所有的$n变量重新计算一遍,所以此时的$0的分隔符就会被指定的OFS替换。

4.NF

Number of Fields,记录了每行数据的字段总数,从1开始计数,值受FS的影响。

[wdy@node1 ~]$ awk 'BEGIN{FS=" "}{print NF,$0}' test1 
3 A B C
3 D E F
2 G H

5.ARGIND

Argument Index,用来标识当前处理的文件序号,从1开始计数。

[wdy@node1 ~]$ awk 'BEGIN{FS=""} {print ARGIND,$0}' test1 test1 
1 A B C
1 D E F
1 G H
2 A B C
2 D E F
2 G H

四、真实业务场景下的一些demo

1.A&B两文件之间做diff,筛选出B中存在A中不存在的行

[wdy@node1 ~]$ cat test1
A B C
D E F
G H[wdy@node1 ~]$ cat test2
A B C
A1 B1 C1
A2 B2 C2[wdy@node1 ~]$ awk 'BEGIN{FS=" "} NR==FNR{a[$0];next} !($0 in a)' test1 test2
A1 B1 C1
A2 B2 C2

上面这段命令,会先以第一个文件中每行记录的值作为数据a的索引建立一个数组a,然后在第二个文件中以每一行的值为索引判断是否在数组a当中,索引不在a中该行记录就会被输出。这里有个点需要注意,就是当动作语句省略时,默认是打印输出当前行。

2.修改文件中字段间的分隔符

[wdy@node1 ~]$ cat test1
A B C
D E F
G H[wdy@node1 ~]$ awk 'BEGIN{FS=" ";OFS="\t"} $1=$1{print $0}' test1
A       B       C
D       E       F
G       H

五、相关面试题

1.词频统计

[wdy@node1 ~]$ cat data 
A B A
C D A
B C A[wdy@node1 ~]$ cat data | awk '
> BEGIN{OFS="\t"}
> {for(i=1;i<=NF;i++) freq[$i]++}
> END{for(word in freq) print word,freq[word]}' | sort -rnk 2
A       4
C       2
B       2
D       1

主要思路是循环遍历每行中的各个字段,以字段值为索引建立数组freq,如果遇到相同的索引则对应索引位置处的值+1。最后打印这个数组结果就可以了。后面的sort命令是对结果进行下排序输出。
关于sort命令,参数代表的含义:
-r:reverse,逆序输出
-n:numeric-sort,根据字符串对应的数值大小来排序,而非字符串的字典顺序。这里是统计频次。
-k:key,指定用来排序的key,上面用2来指定根据频次排序,2代表的是第2列。

PS

实现awk词频统计过程中发现了个问题,当直接在虚拟机中vim新建data文件时,结果正常:

[wdy@node1 ~]$ cat data | awk '
> BEGIN{OFS="\t"}
> {for(i=1;i<=NF;i++) freq[$i]++}
> END{for(word in freq) print word,freq[word]}' | sort -rnk 2
A       4
C       2
B       2
D       1

当在本地(win10)建好数据文件上传到虚拟机中时,结果错误:

[wdy@node1 ~]$ cat data_win | awk '
> BEGIN{OFS="\t"}
> {for(i=1;i<=NF;i++) freq[$i]++}
> END{for(word in freq) print word,freq[word]}' | sort -rnk 2
A       3
C       2
B       2
D       1
A       1

也就是A本来是4,在后面被拆分成了3+1。

查看一下两文件中的全部内容有什么区别:

[wdy@node1 ~]$ cat -A data
A B A$
C D A$
B C A$[wdy@node1 ~]$ cat -A data_win 
A B A^M$
C D A^M$
B C A^M$

Unix/Linux系统中,cat -A命令用于显示文件中的控制字符和非打印字符。在cat -A的输出中,$符号通常用来表示行尾,而M通常表示一个回车符(Carriage Return)。

问题就出现在这,win10上传的文件换行符和linux系统的换行符不一致,虽然不影响awk对行的划分,但是对于除了(1, 1)位置的A,data时A不变,而在data_win中就变成了A\r这个整体,验证一下想法是否正确:

[wdy@node1 ~]$ cat data_win | awk '
> BEGIN{OFS="\t"}
> {for(i=1;i<=NF;i++) freq[$i]++}
> END{for(word in freq) print word,freq[word]}' | sort -rnk 2| cat -A
A^M^I3$
C^I2$
B^I2$
D^I1$
A^I1$

可以看到,之所以上面A分两次输出,就是因为其中有的A附带的有隐藏字符。这个问题可以通过dos2unix data_win转换一下文本格式解决:

[wdy@node1 ~]$ dos2unix data_win
[wdy@node1 ~]$ cat -A data_win 
A B A$
C D A$
B C A$[wdy@node1 ~]$ cat data_win | awk '
> BEGIN{OFS="\t"}
> {for(i=1;i<=NF;i++) freq[$i]++}
> END{for(word in freq) print word,freq[word]}' | sort -rnk 2
A       4
C       2
B       2
D       1

调试过程中还发现一个需要注意的地方,linux中vim编辑器创建的文本,哪怕最后一行没有手动换行,系统也会给最后一行添加换行符,windows中用文本编辑器创建不会。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/319265.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构——循环结构:for循环

今天是星期五&#xff0c;明天休息&#xff0c;后天补课&#xff0c;然后就是运动会&#xff0c;接着是放假。&#xff08;但这些都和我没关系啊&#xff0c;哭死&#xff01;&#xff09;今天脑袋难得清醒一会儿&#xff0c;主要是醒的比较早吧&#xff0c;早起学了一会&#…

3GPP官网下载协议步骤

1.打开官网 https://www.3gpp.org/ 2.点击 3.在界面选择要找的series&#xff0c;跳转到查找界面 以V2X通信协议为例&#xff0c;论文中通常会看到许多应用&#xff1a; [7] “Study on evaluation methodology of new Vehicle-to-Everything (V2X) use cases for LTE and NR…

【Python】机器学习之Sklearn基础教程大纲

机器学习之Sklearn基础教程大纲 1. 引言 机器学习简介Scikit-learn&#xff08;Sklearn&#xff09;库介绍安装和配置Sklearn 2. 数据预处理 2.1 数据加载与查看 - 加载CSV、Excel等格式的数据- 查看数据的基本信息&#xff08;如形状、数据类型等&#xff09;2.2 数据清洗…

大语言模型中的第一性原理:Scaling laws

大语言模型的尺度定律在大语言模型的训练过程中起到了非常重要的作用。即使读者不参与大语言模型的训练过程&#xff0c;但了解大语言模型的尺度定律仍然是很重要的&#xff0c;因为它能帮助我们更好的理解未来大语言模型的发展路径。 1. 什么是尺度定律 尺度定律&#xff08…

anaconda、cuda、tensorflow、pycharm环境安装

anaconda、cuda、tensorflow、pycharm环境安装 anaconda安装 anaconda官方下载地址 本文使用的是基于python3.9的anaconda 接下来跟着步骤安装&#xff1a; 检验conda是否成功安装 安装CUDA和cuDNN 提醒&#xff0c;CUDA和cuDNN两者必须版本对应&#xff0c;否者将会出错…

AI家居设备的未来:智能家庭的下一个大步

&#x1f512;目录 ☂️智能家居设备的发展和AI技术的作用 ❤️AI技术实现智能家居设备的自动化控制和智能化交互的依赖 AI家居设备的未来应用场景 &#x1f4a3;智能家庭在未来的发展和应用前景 &#x1f4a5;智能家居设备的发展和AI技术的作用 智能家居设备的发展和AI技术的…

【skill】onedrive的烦人问题

Onedrive的迷惑行为 安装Onedrive&#xff0c;如果勾选了同步&#xff0c;会默认把当前用户的数个文件夹&#xff08;桌面、文档、图片、下载 等等&#xff09;移动到安装时提示的那个文件夹 查看其中的一个文件的路径&#xff1a; 这样一整&#xff0c;原来的文件收到严重影…

使用Python实现二维码生成工具

二维码的本质是什么&#xff1f; 二维码本质上&#xff0c;就是一段字符串。 我们可以把任意的字符串&#xff0c;制作成一个二维码图片。 生活中使用的二维码&#xff0c;更多的是一个 URL 网址。 需要用到的模块 先看一下Python标准库&#xff0c;貌似没有实现这个功能的…

将要上市的自动驾驶新书《自动驾驶系统开发》中摘录各章片段 1

以下摘录一些章节片段&#xff1a; 1. 概论 自动驾驶系统的认知中有一些模糊的地方&#xff0c;比如自动驾驶系统如何定义的问题&#xff0c;自动驾驶的研发为什么会有那么多的子模块&#xff0c;怎么才算自动驾驶落地等等。本章想先给读者一个概括介绍&#xff0c;了解自动驾…

IoTDB 入门教程 基础篇⑨——TsFile导入导出工具

文章目录 一、前文二、准备2.1 准备导出服务器2.2 准备导入服务器 三、导出3.1 导出命令3.2 执行命令3.3 tsfile文件 四、导入4.1 上传tsfile文件4.2 导入命令4.3 执行命令 五、查询六、参考 一、前文 IoTDB入门教程——导读 数据库备份与迁移是数据库运维中的核心任务&#xf…

Dockerfile实战(SSH、Systemctl、Nginx、Tomcat)

目录 一、构建SSH镜像 1.1 dockerfile文件内容 1.2 生成镜像 1.3 启动容器并修改root密码 二、构建Systemctl镜像 2.1 编辑dockerfile文件 ​编辑2.2 生成镜像 2.3 启动容器&#xff0c;并挂载宿主机目录挂载到容器中&#xff0c;然后进行初始化 2.4 进入容器验证 三、…

如何为 Nestjs 编写单元测试和 E2E 测试

前言 最近在给一个 nestjs 项目写单元测试&#xff08;Unit Testing&#xff09;和 e2e 测试&#xff08;End-to-End Testing&#xff0c;端到端测试&#xff0c;简称 e2e 测试&#xff09;&#xff0c;这是我第一次给后端项目写测试&#xff0c;发现和之前给前端项目写测试还…

可视化大屏C位图:流程图、拓扑图、组态图等

Hello&#xff0c;我是大千UI工场&#xff0c;本期可视化大屏的焦点图&#xff08;C位&#xff09;分享将图表作为焦点图的情形&#xff0c;欢迎友友们关注、评论&#xff0c;如果有订单可私信。 在可视化设计中&#xff0c;将流程图、组态图、拓扑图等作为焦点图有以下几个作用…

Vue3人员选择组件封装

一、组件介绍 人员组件在各系统的应用都是比较广泛的&#xff0c;因此可以将其封装为可配置的人员组件&#xff0c;根据不同角色权限显示对应的人员供选择&#xff0c;代码目前只是一部分&#xff0c;需要源码的私聊。 二、直接上代码 use.vue 父组件 <div class&q…

前端计算机网络之网络模型

什么是网络模型 对于前端开发者而言&#xff0c;理解网络模型的概念是非常重要的。网络模型是描述数据如何在网络中传输和处理的框架和规则&#xff0c;它有助于前端开发者更好地理解和优化应用程序与服务器之间的通信过程。 常用的两类模型 前端开发者需要了解的网络模型主…

【Qt问题】VS2019 Qt win32项目如何添加x64编译方式

解决办法&#xff1a; 注意改为x64版本以后&#xff0c;要记得在项目属性里&#xff0c;修改Qt Settings、对应的链接include、lib等 参考文章 VS2019 Qt win32项目如何添加x64编译方式_vs2019没有x64-CSDN博客 有用的知识又增加了~

SpringBoot配置文件

目录 1 SpringBoot配置文件 2 配置文件的快速入手 3 配置文件格式 4 properties配置文件说明 4.1 properties基本语法 4.2 读取配置文件 4.3 properties缺点 5 yml配置文件 5.1 yml基本语法 5.2 yml配置不同数据类型及null 5.3 配置对象 5.4 配置集合 5.5 配置Map 5.6 yml优缺…

时间日志格式的统一和定制

返回当前格式的时间没有错误&#xff0c;但是不符合中国人的阅读习惯 解决&#xff1a; 方案一&#xff1a;JsonFormat 解决后端 传到 前端格式问题 依赖&#xff1a; <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jack…

掌握JavaScript面向对象编程核心密码:深入解析JavaScript面向对象机制对象概念、原型模式与继承策略全面指南,高效创建高质量、可维护代码

ECMAScript&#xff08;简称ES&#xff0c;是JavaScript的标准规范&#xff09;支持面向对象编程&#xff0c;通过构造函数模拟类&#xff0c;原型链实现继承&#xff0c;以及ES6引入的class语法糖简化面向对象开发。对象可通过构造函数创建&#xff0c;使用原型链共享方法和属…

关于MS-DOS时代的回忆

目录 一、MS-DOS是什么&#xff1f; 二、MS-DOS的主要功能有哪些&#xff1f; 三、MS-DOS的怎么运行的&#xff1f; 四、微软开源MS-DOS源代码 五、高手与漂亮女同学 一、MS-DOS是什么&#xff1f; MS-DOS&#xff08;Microsoft Disk Operating System&#xff09;是微软公…