深入 awk 命令:Linux 命令行中的文本处理神器

文摘   2024-11-13 09:04   广东  

点击上方【蓝字】关注博主

 awk 是一种强大而灵活的文本处理工具,广泛应用于 Linux 命令行环境中。其设计初衷是提供便捷的方式来处理和分析结构化文本数据、行列数据等。通过简单且易于理解的语法,用户能够快速实现数据筛选、格式化和计算。本文将深入探讨 AWK 的基本概念、结构及常用功能。

01

概述

awk 是一种强大的文本处理工具,最早由 Alfred Aho、Peter Weinberger 和 Brian Kernighan 三位计算机科学家在 1977 年开发,因此取名为 “awk”。他们的目标是提供一种便捷的方式来处理和分析结构化文本数据,特别是针对行和列的格式化数据,如表格和日志文件。

awk 的命名源自三位创始人的姓氏首字母(Aho, Weinberger, Kernighan)。起初,awk 主要用于简单的文本处理和转换。随着使用需求的增加,awk 在后来的版本中添加了更多复杂的功能,如支持正则表达式、内置变量、数组等。

awk 的最初版本使用简单,但功能强大。gawk(GNU AWK)是GNU 项目的一部分,扩展了 awk 的功能,增加了许多新特性,比如用户自定义函数和更强大的模式匹配能力。nawk(New AWK)也是 awk的一个改进版本,主要在 1985 年推出,提供额外功能和兼容性。

awk的应用:

  • 常用于系统管理、数据分析和报告生成等多种领域,其主要优势在于对文本数据的高度灵活性和强大的处理能力。

  • 语法简洁明了,非常适合快速编写脚本,进行数据提取和转换。

awk 在文本处理中的重要性:

  1. awk 设计初衷是用于文本处理,特别是结构化文本(如 CSV 和日志文件)。其内置的模式匹配和字段处理功能使得处理文本数据的效率非常高。

  2. awk 的语法相对简洁,可以用较少的代码实现复杂的文本处理逻辑。这使得编写和维护脚本变得更加容易,特别适合快速的数据处理任务。

  3. awk 支持强大的模式匹配功能,包括正则表达式。

  4. awk 提供了一系列内置变量(如 $0, $1, NF, NR 等),以及丰富的内置函数,简化用户在数据处理时的复杂性。用户可以轻松实现各种统计和分析功能。

  5. awk 可以与其他命令行工具(如 grep 和 sed)结合使用,形成强大的文本处理管道,极大地扩展了 awk 的应用场景。

  6. 尽管 awk 主要用于文本处理,但它也能执行数值计算、格式化输出等多种功能。

02

awk 基础知识

2.1、什么是 awk ?

awk 同 sed 命令类似,都是一种文本处理工具,只不过 sed 擅长取行, awk 命令擅长取列。awk 广泛用于 Linux 和 Unix 系统的命令行环境中。它以其简洁的语法和强大的功能而著称,特别适合于对结构化文本数据的处理,如表格、日志文件和配置文件等。

定义: awk 是一种编程语言,用于在文件或标准输入中进行模式匹配和操作。它的语法允许用户定义规则和操作,能够处理文本的行与列。

主要作用:

  1. 文本过滤:awk 可以根据用户定义的模式筛选文本,提取符合条件的行或字段。

  2. 文本格式化:能够对输入的文本进行格式化输出,比如调整列宽、添加文本等。

  3. 字段处理:awk 默认将每一行文本分割成多个字段(以空格或指定分隔符为界),用户可以方便地访问和操作这些字段。

  4. 数值计算:awk 支持多种数值运算,能对数据进行计算,如求和、平均等。

  5. 报告生成:可以基于处理结果生成总结性报告,方便数据分析和展示。

  6. 脚本编写:awk 可用于编写复杂的文本处理脚本,易于部署和执行。

awk 命令基本语法格式为:

awk 'pattern { action }' file
  • pattern:用于匹配输入行的条件。

  • action:对匹配到的行执行的操作。

例子:

  1. 打印文件的每一行:

    awk '{ print }' filename
  2. 打印指定列(如第二列):

    awk '{ print $2 }' filename
  3. 根据条件筛选行(如打印大于某值的行):

    awk '$1 > 10 { print }' filename
  4. 计算某列的总和:

    awk '{ sum += $1 } END { print sum }' filename

原理: 一般是遍历一个文件中的每一行,然后分别对文件的每一行进行处理。

用法:

awk [可选的命令行选项] 'BEGIN{命令 } pattern{ 命令 } END{ 命令 }'  文件名

2.2、awk 的安装与环境

awk 是大多数 Linux 发行版中预装的工具,因此在许多情况下不需要显式安装它。不过,如果你的系统上没有 awk,或者希望安装特定版本,可以按照以下步骤在常见的 Linux 发行版上安装 awk。

在 Debian 或 Ubuntu 及其衍生版上,可以使用 apt 安装 awk(通常是 gawk,GNU AWK 的实现)。

sudo apt update
sudo apt install gawk

在 RHEL、CentOS 或 Fedora 及其衍生版上,可以使用 yum 或 dnf 来安装 awk

# 对于 CentOS/RHEL 7:
sudo yum install gawk

# 对于 Fedora 或 CentOS/RHEL 8:
sudo dnf install gawk

在 Arch Linux 及其衍生版上,可以使用 pacman 安装 awk。

sudo pacman -S gawk

在 OpenSUSE 中,可以使用 zypper 来安装 awk。

sudo zypper install gawk

在 Gentoo 中,可以使用 emerge 来安装 awk。

sudo emerge gawk

安装完成后,可以通过以下命令验证 awk 是否安装成功:

awk --version
03

awk 的基本结构

awk 的基本结构由“模式”(pattern)和“动作”(action)组成。理解这两部分是有效使用 awk 的关键。

模式(pattern)可以是以下几种类型:

  • 行号: 指定执行动作的行,例如 1(第一行)、3(第三行)。

  • 布尔表达式: 可以使用关系运算符(如 ==!=<><=>=)进行比较。例如:$2 > 30(第二列大于 30 的行)。

  • 正则表达式: 使用正则表达式匹配字符串,例如 /pattern/示例:/Alice/(包含 “Alice” 的行)。

  • 内置变量条件: 如 NR(当前记录号)和 NF(当前行字段数)。例如,NF > 2 指示只有当当前行字段数大于 2 时才执行动作。

动作(action)通常由一条或多条语句组成,常见类型包括:

  • 打印: 使用 print 打印输出。示例:{ print $1, $2 } (打印第一和第二列)。

  • 计算: 可以进行简单的算术运算。例如:{ sum += $2 }(将第二列累加到变量 sum)。

  • 赋值和条件控制: 使用变量进行赋值,或者使用 if 语句进行条件控制。

示例 1: 打印所有行。

awk '{ print }' test.txt

示例 2: 只打印第二列大于 30 的行。

awk '$2 > 30 { print $1, $2 }' test.txt

示例 3: 使用正则表达式。

awk '/Alice/ { print $0 }' test.txt

默认行为: 如果没有指定模式,awk 默认会处理每一行;如果没有指定动作,awk 默认会执行 print 动作,打印每一匹配的行。

awk “字段”和“记录”的概念是其核心组成部分。在 awk 中,记录通常是指输入文本中的一行。默认情况下,awk 会将每一行视为一条记录。所有记录的集合构成了 awk 的输入。

每条记录可以进一步划分为多个 字段。awk 默认使用空格和制表符作为字段的分隔符。每个字段可以通过特殊变量 $n 访问,其中 n 是字段的位置。例如:

  • $1 表示第一字段。

  • $2 表示第二字段。

  • 依此类推

awk 默认的字段分隔符是空格( )和制表符(\t)。这意味着空格和制表符被视为将字段分开的字符。

如果需要使用其他字符作为字段分隔符,可以在 awk 命令中使用 -F 选项来修改。例如:

  • 使用逗号 , 作为分隔符:

    awk -F, '{ print $1, $2 }' file.csv
  • 使用冒号 : 作为分隔符:

    awk -F: '{ print $1, $3 }' /etc/passwd

要处理和访问字段,可以使用以下几种方法:

  1. 直接打印字段内容:

    awk '{ print $1, $2 }' test.txt
  2. 计算字段的总和。例如,计算第二列的总和:

    awk '{ sum += $2 } END { print sum }' test.txt
  3. 可以根据字段的值进行条件处理,例如只打印第二列值大于 30 的行:

    awk '$2 > 30 { print $1, $2 }' test.txt

内置变量:

  • NF: 表示当前记录的字段数量,可以用来处理动态字段数量的行。

  • NR: 表示当前记录的行号。

04

awk 的常用功能

打印某几列:

$ echo 'I love you' | awk '{print $3 $2 $1}'
youloveI

我们将字符串 I love you 通过管道传递给awk命令,相当于awk处理一个文件,该文件的内容就是I love you,默认通过空格作为分隔符(不管列之间有多少个空格都将当作一个空格处理)I love you就分割成三列了。假如分割符号为.,可以这样用:

$ echo '192.168.1.1' | awk -F "." '{print $2}'
168

条件过滤:
我们知道awk的用法是这样的,那么pattern部分怎么用呢?

awk [可选的命令行选项] 'BEGIN{命令 } pattern{ 命令 } END{ 命令 }'  文件名
$ cat score.txt
tom 60 60 60
kitty 90 95 87
jack 72 84 99
$ awk '$2>=90{print $0}' score.txt
kitty 90 95 87

$2>=90 表示如果当前行的第 2 列的值大于 90 则处理当前行,否则不处理。说白了 pattern 部分是用来从文件中筛选出需要处理的行进行处理的,这部分是空的代表全部处理。
pattern 部分可以是任何条件表达式的判断结果,例如>,<,==,>=,<=,!=同时还可以使用+,-,*,/运算与条件表达式相结合的复合表达式,逻辑 &&,||,!同样也可以使用进来。另外 pattern 部分还可以使用 /正则/ 选择需要处理的行。

判断语句:
判断语句是写在pattern{ 命令 }命令中的,他具备条件过滤一样的作用,同时他也可以让输出更丰富

$ awk '{if($2>=90 )print $0}' score.txt
kitty 90 95 87
$ awk '{if($2>=90 )print $1,"优秀"; else print $1,"良好"}' score.txt
tom 良好
kitty 优秀
jack 良好
$ awk '{if($2>=90 )print $0,"优秀"; else print $1,"良好"}' score.txt
tom 良好
kitty 90 95 87 优秀
jack 良好

BEGIN 定义表头:

awk [可选的命令行选项] 'BEGIN{命令 } pattern{ 命令 } END{ 命令 }'  文件名

使用方法如下:

$ awk 'BEGIN{print "姓名 语文 数学 英语"}{printf "%-8s%-5d%-5d%-5d\n",$1,$2,$3,$4}' score.txt
姓名 语文数学英语
tom 60 60 60
kitty 90 95 87
jack 72 84 99

这里要注意,我为了输出格式好看,做了左对齐的操作(%-8s左对齐,宽8位),printf用法和c++类似。
不仅可以用来定义表头,还可以做一些变量初始化的工作,例如

$ awk 'BEGIN{OFMT="%.2f";print 1.2567,12E-2}'
1.26 0.12

这里OFMT是个内置变量,初始化数字输出格式,保留小数点后两位。

END 添加结尾符: 和BEGIN用法类似。

$ echo ok | awk '{print $1}END{print "end"}'
ok
end

数据计算:

$ awk 'BEGIN{print "姓名 语文 数学 英语 总成绩"; \
sum1=0;sum2=0;sum3=0;sumall=0} \
{printf "%5s%5d%5d%5d%5d\n",$1,$2,$3,$4,$2+$3+$4;\
sum1+=$2;sum2+=$3;sum3+=$4;sumall+=$2+$3+$4}\
END{printf "%5s%5d%5d%5d%5d\n","总成绩",sum1,sum2,sum3,sumall}'
\
score.txt
姓名 语文 数学 英语 总成绩
tom 60 60 60 180
kitty 90 95 87 272
jack 72 84 99 255
总成绩 222 239 246 707

因为命令太长,末尾用\符号换行。

  • BEGIN体里输出表头,并给四个变量初始化0。

  • pattern体里输出每一行,并累加运算。

  • END体里输出总统计结果。

当然了,一个正常人在用 Linux 命令的时候是不会输入那么多格式化符号来对齐的,所以新命令又来了column -t(鬼知道我为什么会记得这么多乱七八糟的命令)。

awk 支持标准的 if 语句,用于根据条件执行不同的操作。例如:打印第二列大于 30 的行,并标记是否超过 50。

awk '{ 
if ($2 > 50)
print $1, ":", $2, " (High)"
else if ($2 > 30)
print $1, ":", $2, " (Medium)"
else
print $1, ":", $2, " (Low)"
}'
test.txt

awk 提供了一些循环结构,包括 for 循环和 while 循环。例如:

awk 'BEGIN { 
for (i = 1; i <= 5; i++)
print i
}'

awk 'BEGIN { 
i = 1;
while (i <= 5) {
print i;
i++
}
}'
05

awk 范例:网络状态统计

本小节,采用awk统计netstat命令的一些网络状态,来看一下awk语言的基本要素。netstat的输出类似于:

Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 localhost:42373 localhost:52530 ESTABLISHED
tcp 0 0 localhost:42373 localhost:44906 ESTABLISHED
tcp 0 0 localhost:52530 localhost:42373 ESTABLISHED
tcp 0 0 localhost:44906 localhost:42373 ESTABLISHED
tcp 0 0 172.28.129.124:51366 ubuntu-mirror-1.ps:http TIME_WAIT
Active UNIX domain sockets (w/o servers)
Proto RefCnt Flags Type State I-Node Path
unix 2 [ ] DGRAM 18547 /var/run/chrony/chronyd.sock
unix 3 [ ] DGRAM CONNECTED 21586 /run/systemd/notify
unix 2 [ ] DGRAM 20867 /run/user/1000/systemd/notify
unix 2 [ ] DGRAM 21595 /run/systemd/journal/syslog
unix 9 [ ] DGRAM CONNECTED 21603 /run/systemd/journal/dev-log
unix 7 [ ] DGRAM CONNECTED 21605 /run/systemd/journal/socket
unix 3 [ ] STREAM CONNECTED 1368
unix 2 [ ] DGRAM 62094
unix 3 [ ] STREAM CONNECTED 740099
......

其中,第 6 列,标明了网络连接所处于的网络状态。我们先给出awk命令,看一下统计结果。

netstat  -ant | 
awk ' \
BEGIN{print "State","Count" } \
/^tcp/ \
{ rt[$6]++ } \
END{ for(i in rt){print i,rt[i]} }'

netstat -ant |
awk ' \
BEGIN{print "State","Count" } \
/^tcp/ \
{ if($4=="0.0.0.0:3306" ) rt[$6]++ } \
END{ for(i in rt){print i,rt[i]} }'

输出结果为:

State Count
LAST_ACK 1
LISTEN 64
CLOSE_WAIT 43
ESTABLISHED 719
SYN_SENT 5
TIME_WAIT 146

下面这张图会配合以上命令详细说明,希望你能了解awk的精髓。

乍一看,好吓人的命令,但是很简单。awk和我们通常的程序不太一样,它分为四个部分。

  1. BEGIN 开头部分,可选的。用来设置一些参数,输出一些表头,定义一些变量等。上面的命令仅打印了一行信息而已。

  2. END 结尾部分,可选的。用来计算一些汇总逻辑,或者输出这些内容。上面的命令,使用简单的for循环,输出了数组rt中的内容。

  3. Pattern 匹配部分,依然可选。用来匹配一些需要处理的行。上面的命令,只匹配tcp开头的行,其他的不进入处理。

  4. Action 模块。主要逻辑体,按行处理,统计打印,都可以。


注意点:

  • awk的主程序部分使用单引号包围,而不能是双引号

  • awk的列开始的index是 0,而不是1


06

总结

awk 作为一种高效的文本处理工具,其功能强大且灵活,适用于多种数据处理任务。从基础语法到复杂的条件和循环结构,awk 提供了丰富的操作选项。文章通过实例详细介绍了它在文本筛选、格式化输出和数据计算等方面的应用,展示了 awk 在系统管理和数据分析中的重要性。通过掌握 awk,用户不仅能够提升文本处理的效率,还能够轻松编写和维护复杂的脚本,为工作中带来更大的便利。

更进一步学习:https://github.com/Black-Gold/Learn/blob/1ee76ca2a9bbbbfe04850a1ccc9b9658e1eb39de/Linux_man_cn/awk.md

公众号: Lion 莱恩呀

微信号: 关注获取

扫码关注 了解更多内容

点个 在看 你最好看


Lion 莱恩呀
专注分享高性能服务器后台开发技术知识,涵盖多个领域,包括C/C++、Linux、网络协议、设计模式、中间件、云原生、数据库、分布式架构等。目标是通过理论与代码实践的结合,让世界上看似难以掌握的技术变得易于理解与掌握。
 最新文章