【命令行程序】awk 最强大、最实用的文本处理工具

2024-02-10 00:00:00

目录:

awk 介绍

awk 不像 grep 只能查找文本,也不像 sed 只能编辑整行,而是能先把一行文本按空格(或你指定的符号)切成好几块(字段),然后对这些“小块”进行筛选、计算、统计、格式化等操作。

工作原理:

  • 逐行读取:从文件或管道输入中,一次读取一行文本;
  • 切割字段:根据分隔符(默认是空格或制表符),把这行文本切成多个部分,分别称为 $1(第一列)、$2(第二列)…… $0 则代表整行内容;
  • 判断条件:检查这一行是否符合你设定的条件(比如包含某个词,或者行号是第 5 行);
  • 执行动作:如果符合条件,就执行相应的操作(比如打印某一列,或者进行累加计算);
  • 循环往复:重复以上步骤,直到处理完所有行。

更厉害的是,awk 的程序结构由三个清晰的模块组成,执行顺序非常明确:

  • BEGIN 块:在开始读取任何数据之前执行一次。通常用来初始化变量、打印表头;
  • 主体块:对每一行数据都执行一次。这是最核心的部分,用于处理、筛选、计算;
  • END 块:在处理完所有数据之后执行一次。通常用来输出最终的统计结果、汇总信息。

格式: awk 'pattern {action}' 文件名

  • pattern(模式):可选的条件,用来筛选行。如果省略,则对每一行都执行动作;
  • action(动作):对符合条件的行要执行的操作,必须用花括号 {} 括起来;
  • 文件名:要处理的文件。

需要记忆的内置变量:

  • $0 整行内容;
  • $1, $2, … $n 第 1、2…n 个字段;
  • NF 当前这一行总共有多少列。$NF 就代表最后一列,非常有用;
  • NR 当前正在处理的是第几行(从1开始计数);
  • FS 输入字段分隔符,默认为空格/制表符,可以用 -F 选项修改,比如 -F: 表示用冒号分隔;
  • OFS 输出字段分隔符,打印时,字段之间用什么隔开,默认是空格。

查看当前目录下所有文件的大小

命令 ls -l 会输出很多信息,但我们可能只关心文件名(第9列)和大小(第5列)

$ ls -l | awk '{print $9, $5}'

提取系统用户信息

/etc/passwd 文件保存了用户信息,字段用冒号 : 分隔。
我们想提取用户名(第1列)和使用的 Shell(最后一列)。

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

找出磁盘使用率超过 80% 的分区

$ df -h
Filesystem        Size    Used   Avail Capacity iused ifree %iused  Mounted on
/dev/disk3s1s1   460Gi    11Gi    92Gi    12%    453k  961M    0%   /
devfs            208Ki   208Ki     0Bi   100%     720     0  100%   /dev
/dev/disk3s6     460Gi   7.0Gi    92Gi     8%       7  961M    0%   /System/Volumes/VM

$ df -h | awk '$5+0 > 80 {print $1, $5}'

df -h 查看磁盘使用情况,第 5 列是使用率(带 % 号)。$5+0 是为了把带 % 的字符串转换成数字,以便进行大小比较(> 80)。

显示非注释行

在配置文件(如 /etc/fstab)中,想只看有效的配置行,忽略以 # 开头的注释行。

$ awk '$1 !~ /^#/ && NF > 0 {print $0}' /etc/fstab
  • $1 !~ /^#/ 表示第一列不以 # 开头;
  • NF > 0 确保不是空行。

统计文本中数字的总和

假设有一个文件 numbers.txt,每行只有一个数字。

$ awk '{sum += $1} END {print "总和是:", sum}' numbers.txt

对每一行的第一列($1)进行累加(sum += $1),处理完所有行后,在 END 块中打印总和。

统计访问日志中最活跃的 IP

假设 access.log 的第一列是IP地址。

$ awk '{ip[$1]++} END {for (i in ip) print ip[i], i}' access.log | sort -nr | head -5

这里用到了数组 ip,以 IP 地址为下标进行计数。END 块中遍历数组并打印每个 IP 及其出现次数,最后通过管道 | 排序并取前 5 名。

批量替换文本

将文件中所有的 “old” 替换为 “new”,gsub 是全局替换函数。

$ awk '{gsub(/old/, "new", $0); print}' file.txt

返回首页

本文总阅读量  次
皖ICP备17026209号-3
总访问量: 
总访客量: