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

linux中的awk使用详解

文章目录

  • 前言
  • 一、概述
  • 二、工作原理
  • 三、工作流程
    • 3.1 运行模式
    • 3.2 执行流程
  • 四、基本语法
    • 4.1 命令格式
    • 4.2 常用内置变量
  • 五、实战案例
    • 5.1 基础文本处理
    • 5.2 模式匹配
    • 5.3 使用 BEGIN 和 END
      • 5.3.1 直接数学运算
    • 5.4 模糊匹配
    • 5.5 逻辑运算与条件判断
    • 5.6 使用awk的内置变量
    • 5.7 在awk中使用if进行逻辑控制
    • 5.8 通过管道、双引号调用shell 命令
    • 5.9 数组与循环
      • 5.9.1 核心概念:AWK 数组是**关联数组**
      • 5.9.2 基本语法
      • 5.9.3 关键特性与用法
        • 5.9.3.1 遍历数组
        • 5.9.3.2 检查键是否存在以及检查数组是否为空
        • 5.9.3.3 删除数组元素
        • 5.9.3.4 多维数组(模拟)
      • 5.9.4 经典实用示例
        • 5.9.4.1 示例 1:统计词频
        • 5.9.4.2 示例 2:处理 /etc/passwd 文件
        • 5.9.4.3 示例 3:倒置数组(键值互换)
      • 5.9.4.3 总结与注意事项
    • 5.10实战脚本示例
      • 5.10.1 查看内存百分比
        • 5.10.1.1 从`/proc/meminfo`获取参数实现内存百分比计算
      • 5.10.2 同一ip多次失败访问预警
      • 5.10.3 统计在线用户
      • 5.10.4 查看cpu使用率
  • 总结


前言

AWK 是一种强大的文本处理工具,诞生于 20 世纪 70 年代的贝尔实验室,由 Alfred Aho、Peter Weinberger 和 Brian Kernighan 三位创始人共同开发,其名称取自三人姓氏的首字母。AWK 专门用于文本扫描、过滤、统计和格式化输出,支持从标准输入、管道或文件中读取数据。在 Linux 系统中,常用的版本是 GAWK(GNU AWK),它是 AWK 的自由软件版本,完全兼容 AWK 和 NAWK。

本文将系统介绍 AWK 的基本概念、工作原理、语法结构、常用变量和实战案例,帮助读者全面掌握 AWK 的使用方法。


一、概述

AWK 是一种处理文本文件的编程语言,也是一个强大的文本分析工具。它逐行读取输入数据,按字段进行处理,支持模式匹配、变量操作、数学运算和流程控制,广泛应用于日志分析、数据提取和报表生成等场景。

二、工作原理

AWK 逐行读取文本,默认以空格或制表符作为字段分隔符,将每行拆分成多个字段,并存入内置变量(如 $1$2 等)。每读取一行,AWK 会检查是否匹配指定的模式,若匹配则执行相应的动作。若不指定模式,则默认处理所有行。

三、工作流程

3.1 运行模式

任何 awk 语句都是由模式和动作组成,一个 awk 可以有多个语句。模式决定动作语句的触发条件触发时间

AWK 程序由三部分组成:

  • BEGIN 块:在处理输入前执行一次,常用于初始化变量或打印表头。
  • pattern { action } 块:对每一行进行模式匹配,若匹配则执行动作。
  • END 块:在处理完所有输入后执行一次,常用于汇总结果。

3.2 执行流程

  1. 执行 BEGIN 块中的命令。
  2. 逐行读取输入数据。
  3. 对每一行执行匹配的模式和动作。
  4. 重复步骤 2 和 3,直到所有行处理完毕。
  5. 执行 END 块中的命令。

四、基本语法

4.1 命令格式

awk [选项] '模式 { 动作 }' 文件1 文件2 ...
awk -f 脚本文件 文件1 文件2 ...

4.2 常用内置变量

AWK 支持两种不同类型的变量:内建变量(可直接使用),自定义变量awk 内置变量(预定义变量)

变量名说明
FS输入字段分隔符,默认为空格或制表符
OFS输出字段分隔符,默认为空格
RS输入行分隔符,默认为换行符
ORS输出行分隔符,默认为换行符
NF当前行的字段数
NR当前行号
FNR当前文件的行号(多文件时独立计数)
$0当前行的完整内容
$n当前行的第 n 个字段
FILENAME当前输入文件名

五、实战案例

5.1 基础文本处理

# 打印文件所有行
awk '{print}' zz

在这里插入图片描述

# 打印第一列
awk '{print $1}' zz #因没有定义分隔符,按默认分隔符空格进行分段

在这里插入图片描述

# 指定冒号为分隔符,打印第五列
awk -F: '{print $5}' zz

在这里插入图片描述

#定义多个分隔符,只要看到其中一个都算作分隔符
awk -F[:/] '{print $9}' zz 

在这里插入图片描述

#显示一个空格,空格需要用双引号引起来,如果不用引号默认以变量看待,如果是常量就需要双引号引起来awk '{print $1""$2}' zz #逗号有空格效果awk '{print $1,$2}' zz #用制表符作为分隔符输出awk -F: '{print $1"\t"$2}' zz

在这里插入图片描述

# 打印行号和整行内容
awk '{print NR, $0}' zz

在这里插入图片描述

5.2 模式匹配

# 打印包含 "root" 的行
awk -F: '/root/{print $0}' zz
# 打印包含 "root" 的行的第一列
awk -F: '/root/{print $1}' pass.txt

在这里插入图片描述
在这里插入图片描述

#显示行号
awk -F: '{print NR}' zz

在这里插入图片描述

#打印总行数
awk 'END{print NR}' zz 
#打印文件最后一行
awk 'END{print $0}' zz

在这里插入图片描述
在这里插入图片描述

#打印第二行的第一列
awk -F: 'NR==2{print $1}'
#打印最后一列
awk -F: '{print $NF}' zz

在这里插入图片描述

#打印第二行,不加print也一样,默认就是打印
awk 'NR==2' zz
awk 'NR==2{print}' zz

在这里插入图片描述

# 打印第三列等于 0 的行
awk -F: '$3 == 0' zz

在这里插入图片描述

# 打印行号小于 5 的行
awk 'NR < 5' zz

在这里插入图片描述

#不将字符串用双引号框起来会无法进行判断
awk -F: '$1==root' /etc/passwd
#精确匹配一定是root 
awk -F: '$1=="root"' /etc/passwd

在这里插入图片描述

awk -F: '$3>=1000' /etc/passwd

在这里插入图片描述

5.3 使用 BEGIN 和 END

  • BEGIN一般用来做初始化操作,仅在读取数据记录之前执行一次
  • END一般用来做汇总操作,仅在读取完数据记录之后执行一次
awk -F: 'BEGIN{x=0};/\/bin\/bash$/{x++;print x,$1};END{print "bash的目录为/bin/bash的用户共"x"个"}' /etc/passwd

在这里插入图片描述

5.3.1 直接数学运算

awk 'BEGIN{x=10;print x}' #赋值变量
awk 'BEGIN{x=10;print x+1}' #变量运算
awk 'BEGIN{x=10;x++;print x}' #变量自增
awk 'BEGIN{print x+1}' #直接输出变量不定义变量,默认为0
awk 'BEGIN{print 2.5+3.5}' #小数计算
awk 'BEGIN{print 2-1}' #减
awk 'BEGIN{print 3*4}' #乘
awk 'BEGIN{print 3**2}' #开平方
awk 'BEGIN{print 2^3}' #指数幂
awk 'BEGIN{print 1/2}' #除法

在这里插入图片描述

5.4 模糊匹配

# 打印第一列包含 "root" 的行,模糊匹配
awk -F: '$1 ~ /root/' zz
# 打印第一列包括ro的所有行
awk -F: '$1~/ro/' zz
# 打印第七列不是nologin的所有行中的第一列和第七列
awk -F: '$7!~/nologin$/{print $1,$7}' zz

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.5 逻辑运算与条件判断

  • 条件判断
    使用==!=<=>=<>等符号
  • 逻辑运算
    使用&&||符号
  • && 要求所有条件都为真时才为真,否则为假。
  • || 只要有一个条件为真就为真,全为假时才为假。
# 打印第三列小于10或大于等于1000的行
awk -F: '$3 < 10 || $3 >= 1000' /etc/passwd

在这里插入图片描述

 awk -F: '!($3<200){print}' /etc/passwd

在这里插入图片描述

5.6 使用awk的内置变量

awk 'BEGIN{FS=":"}{print $1}' zz

在这里插入图片描述

awk 'BEGIN{FS=":";OFS="abc"}{print $1,$3}' zz

在这里插入图片描述

 awk '{print FNR,$0}' /etc/passwd zz

在这里插入图片描述

在这里插入图片描述

awk '{print NR,$0}' zz

在这里插入图片描述

awk 'BEGIN{ORS=" "}{print NR,$0}' zz

在这里插入图片描述

awk 'BEGIN{RS=" "}{print NR,$0}' zz

在这里插入图片描述

5.7 在awk中使用if进行逻辑控制

在awk也可以使用if、while、for等判断控制方法

# 使用 if 语句判断并打印
awk -F: '{if($3 < 10) print $3; else print $1}' /etc/passwd

在这里插入图片描述

5.8 通过管道、双引号调用shell 命令

# 统计使用 bash 的用户数
awk -F: '/bash$/{print | "wc -l"}' /etc/passwd

在这里插入图片描述

#显示查看PATH中的查找路径
echo $PATH | awk 'BEGIN{RS=":"}{print NR,$0}END{print NR}'

在这里插入图片描述

5.9 数组与循环

5.9.1 核心概念:AWK 数组是关联数组

AWK 中的数组与大多数编程语言中的数组(如 C 或 Java)有根本性的不同。它们不是通过数字索引(0, 1, 2, …)来访问的,而是通过字符串来索引的。这种数据结构在其他语言中通常被称为字典(Dictionary)映射(Map)哈希表(Hash)

这意味着你可以使用任何字符串作为数组的“下标”或“键(key)”。

5.9.2 基本语法

  1. 定义与赋值:无需预先声明大小或类型,直接赋值即可创建,index可以是任意字符串

    # 基本赋值
    array[index] = value# 示例
    array["name"] = "Alice"
    array[1] = "Number One" # 注意:这里的 1 会被 AWK 理解为字符串 "1"
    array[var] = 42        # 使用变量 var 的值作为键
    
  2. 读取值:通过键名来访问对应的值。

    print array["name"]  # 输出:Alice
    print array[1]       # 输出:Number One
    

5.9.3 关键特性与用法

5.9.3.1 遍历数组

这是使用 AWK 数组最常见的操作之一,使用特殊的 for...in 循环。

for (key in array) {print key, array[key] # 打印键和对应的值
}
# 定义数组并遍历
awk 'BEGIN{a['abc']=10; a['456']=20; for(i in a) print i, a[i]}'

在这里插入图片描述

重要提示for (key in array) 循环中,键的遍历顺序是随机的,不保证与赋值的顺序相同。如果需要按特定顺序处理,需要自行对键进行排序。如上图所示,虽然先添加了a["abc"]但实际先打印的是a["456"]

5.9.3.2 检查键是否存在以及检查数组是否为空

使用 in 操作符来检查一个键是否存在于数组中。

if (key in array) {print "键" key "存在于arryay中,它的值为:”, array[key]
} else {print " 键"Key "不存在于arrat"中
}
awk 'BEGIN{a["abc"]=1;a["456"]=2; key="789";if( key in a ){print "键" key "存在于a中,它的值为:",a[key]}else{print "键" key "不存在于a中" }}'

在这里插入图片描述

注意:不能通过检查 array["key"] 是否为空或 0 来判断,因为它的值可能就是空或 0。

#判断数组为空的方法为判断数组的长度
if (length(array) == 0) {print "数组为空"
} else {print "数组不为空,有", length(array), "个元素"
}
awk 'BEGIN{a["abc"]=1;a["456"]=2;if( length(a) == 0 ){ print "数组为空"}else{print "数组不为空,有", length(a), "个元素" }}'awk 'BEGIN{if( length(a) == 0 ){ print "数组为空"}else{print "数组不为空,有", length(a), "个元素" }}'

在这里插入图片描述

5.9.3.3 删除数组元素

使用 delete 语句来移除数组中的一个键值对。

delete array["name"] # 删除键为 "name" 的元素

如果要清空整个数组,可以遍历删除所有元素,或者直接使用 split() 函数重新赋值(一种常见技巧)。

# 方法一:遍历删除(安全)
for (key in array) {delete array[key]
}# 方法二:更快的清空方法
split("", array) # 将一个空字符串分割后存入 array,效果是清空 array
awk 'BEGIN{a["abc"]=1;a["456"]=2;delete a["456"];for(i in a) print i, a[i]}'
awk 'BEGIN{a["abc"]=1;a["456"]=2;split("", a);for(i in a) print i, a[i]}'

在这里插入图片描述

5.9.3.4 多维数组(模拟)

AWK 本身不支持真正的多维数组,但它提供了一个非常强大的特性来模拟它:你可以使用 SUBSEP 作为分隔符来组合键名

内置变量 SUBSEP 默认值是 \034(一个不可打印的字符)。

# 模拟一个 2x2 的多维数组
array["1", "1"] = "Top-Left"
array["1", "2"] = "Top-Right"
array["2", "1"] = "Bottom-Left"
array["2", "2"] = "Bottom-Right"# 上面的赋值在内部等价于:
# array["1" SUBSEP "1"] = "Top-Left"
# array["1\0341"] = "Top-Left"# 访问元素
print array["1", "2"] # 输出:Top-Right# 遍历多维数组
for (key in array) {print "Key:”, key, "Value:”, array[key]
}
# 输出可能是:
# Key: 1□1 Value: Top-Left  (□ 代表不可见的 SUBSEP)
# Key: 1□2 Value: Top-Right
# ...

5.9.4 经典实用示例

5.9.4.1 示例 1:统计词频

这是 AWK 数组的“杀手级”应用。

# 输入:text.txt
apple banana
apple orange banana
orange# AWK 命令
awk '
{for (i=1; i<=NF; i++) { # 遍历每一行的每个字段(单词)count[$i]++         # 以单词作为键,出现次数作为值,进行累加}
}
END {for (word in count) {print word, count[word]}
}' text.txt

输出(顺序可能随机):

apple 2
banana 2
orange 2
5.9.4.2 示例 2:处理 /etc/passwd 文件
# 将用户ID($3)作为键,用户名($1)作为值,存入数组
awk -F: '{ users[$3] = $1 } END { for (uid in users) print "UID:”, uid, "-> User:”, users[uid] }' /etc/passwd
5.9.4.3 示例 3:倒置数组(键值互换)
# 假设有一个原始数组 original
original["a"] = 10
original["b"] = 20# 创建倒置数组 inverted
for (key in original) {inverted[original[key]] = key
}# 现在 inverted[10] 的值是 "a",inverted[20] 的值是 "b"
# 统计 IP 出现次数
awk '{ip[$1]++} END{for(i in ip) print ip[i], i}' /var/log/httpd/access_log | sort -nr

5.9.4.3 总结与注意事项

特性描述
类型关联数组(字典/哈希表)
索引字符串(即使是数字也会被转为字符串处理)
顺序遍历顺序随机,不保证插入顺序
检查存在使用 (key in array)
删除元素使用 delete array[key]
多维数组使用 array[i, j] 语法模拟,内部是 i SUBSEP j

优势

  • 极其强大和灵活:文本处理、统计、数据关联的利器。
  • 使用简单:无需声明,自动增长。

需要注意的点

  • 性能:对于海量数据(例如上百万个键),AWK 数组的性能可能不如专门的编程语言,但对于大多数日常的日志分析、文本处理任务来说绰绰有余。
  • 顺序:如果需要按特定顺序输出,必须自己对键进行排序。可以在 AWK 内部实现一个排序算法,或者使用 asort()/asorti() 函数(GNU AWK 支持),更常见的做法是将键输出并通过管道传递给系统命令 sort

5.10实战脚本示例

5.10.1 查看内存百分比

通过判断百分比是否到达阈值可以进行预警,如通过发送邮件等方式。

# 查看内存使用百分比
free -m | awk '/Mem:/{print "当前内存已经使用了"int((1-$7/$2)*100)"%"}'

从 Linux 内核 3.14 版本开始,free 命令引入了 available 列。这个值是一个估算,表示在不进行交换(swap)的情况下,可供新应用程序使用的内存大小。它考虑了 free 内存和大部>分可回收的 cache/buffer 内存。
因此,最准确的计算当前内存使用百分比的公式是:
内存使用率 = (1 - (available / total)) * 100%

在这里插入图片描述

5.10.1.1 从/proc/meminfo获取参数实现内存百分比计算

比起使用free -h获取内存参数,更推荐从/proc/meminfo中获得更真实的数据。

#!/bin/bash# 从 /proc/meminfo 读取关键值
mem_total=$(grep MemTotal /proc/meminfo | awk '{print $2}')
mem_available=$(grep MemAvailable /proc/meminfo | awk '{print $2}')# 计算使用率百分比
mem_used_percentage=$(echo "scale=2; (1 - $mem_available / $mem_total) * 100" | bc)echo "内存总大小: $(echo "scale=2; $mem_total / 1024" | bc) MB"
echo "可用内存: $(echo "scale=2; $mem_available / 1024" | bc) MB"
echo "当前内存使用率: $mem_used_percentage%"

为什么推荐 /proc/meminfo?
它是 free、top 等命令的数据来源,是“真相之源”。
输出格式稳定,不会因 free 命令版本不同而改变字段顺序。
MemAvailable 是内核直接提供的估算值,比用 (free + buff/cache) 的旧方法更智能、更准确。

也可以将这个变成脚本中的函数,提高复用性。

#!/bin/bash
mem_total=$(awk '/MemTotal/{print $2}' /proc/meminfo)
mem_available=$(awk '/MemAvailable/{print $2}' /proc/meminfo)getMem(){local mem_per=$(echo "scale=2;(1 - $mem_available / $mem_total) * 100" | bc)local mem_tatol_mb=$(echo "scale=2;$mem_total / 1024" | bc)local mem_ava_mb=$(echo "scale=2;$mem_available / 1024" | bc)echo "$mem_per $mem_tatol_mb $mem_ava_mb"
}

通过调用函数获取到内存的三个数值. ./mem_stats.sh | read mem_usage mem_total mem_ava

5.10.2 同一ip多次失败访问预警

#!/bin/bash
log="/var/log/secure"
result=$(awk '/Failed password/{ip[$11]++} END{for(i in ip) print i","ip[i]}' $log)for line in $result; doip=$(echo $line | cut -d, -f1)count=$(echo $line | cut -d, -f2)if [ $count -ge 3 ]; thenecho "警告!$ip 访问本机失败了 $count 次,请速处理!"fi
done

/var/log/secure是登录失败日志

5.10.3 统计在线用户

awk 'BEGIN {n=0 ; while ("w" | getline) n++ ; {print n-2}}'
#调用w命令,并用来统计在线用户数

在这里插入图片描述

5.10.4 查看cpu使用率

cpu_us=$(top -bn1 | awk '/Cpu/{print $2}')
cpu_sy=$(top -bn1 | awk '/Cpu/{print $4}')
cpu_sum=$(echo "$cpu_us+$cpu_sy" | bc)
echo $cpu_sum

在这里插入图片描述

总结

AWK 是一款功能强大的文本处理工具,具备以下特点:

  • 灵活性强:支持字段分隔、模式匹配、变量操作、数学运算和流程控制。
  • 适用场景广:可用于日志分析、数据提取、报表生成等。
  • 与 Shell 结合紧密:可通过管道调用其他命令,增强处理能力。

grepsed 相比,AWK 更擅长对结构化文本进行复杂处理和格式化输出。掌握 AWK 的使用,能极大提升在 Linux 环境下的文本处理效率。
最后,希望大家多多实践,夯实基础,聚沙成塔,与君共勉之!

http://www.xdnf.cn/news/1459333.html

相关文章:

  • 深度解读《实施“人工智能+”行动的意见》:一场由场景、数据与价值链共同定义的产业升级
  • 【8】C#上位机---泛型、委托delegate与多线程Task
  • 2025年代理IP服务深度评测:三大平台横评,谁是最强业务助手?
  • 检查数据集格式(77)
  • 计算机二级C语言操作题(填空、修改、设计题)——真题库(16)附解析答案
  • C++基础——模板进阶
  • 【C++题解】关联容器
  • Linux的权限详解
  • 一次死锁的排查
  • 激活函数:神经网络的“灵魂开关”
  • 阅读论文神奇Zotero下载安装教程以及划词翻译(Translate for Zotero)的配置
  • 动态内存管理柔性数组
  • Vue 中绑定样式的几种方式
  • Process Explorer 学习笔记(第三章3.1.1):度量 CPU 的使用情况详解
  • 【Unity知识分享】Unity接入dll调用Window系统接口
  • 无限时长视频生成新突破!复旦联合微软、腾讯混元推出StableAvatar,仅需1张照片+1段音频实现真人说话视频
  • hutool的EnumUtil工具类实践【持续更新】
  • 揭秘23种设计模式的艺术与技巧之行为型
  • 美联储计划召开稳定币和代币化创新会议
  • 大数据框架Doris全面解析
  • 期权平仓后权利金去哪了?
  • 基于STM32的智能家居语音控制系统设计
  • Pycharm终端pip install的包都在C:\Users\\AppData\Roaming\Python\解决办法
  • 手写Spring框架
  • 前端跨域终极指南:3 种优雅解决方案 + 可运行 Demo
  • 解密注意力机制:为何它能在Transformer中实现高效并行计算?
  • STM32G4 速度环开环,电流环闭环 IF模式建模
  • 如何在Linux上部署1Panel面板并远程访问内网Web端管理界面
  • Kafka 开启 SASL_PLAINTEXT 双监听器认证(内网/外网)
  • 如何减少文档冗余和重复劳动