十九、awk 命令提取文件中的关键字段

1、awk

是一种强大的文本处理语言,专为按字段(列)分析数据而设计。是类似 sed 的行处理软件,awk信息的读入也是逐行读取的,执行结果可以通过print的功能将字段数据打印显示。

  • gawk 是 GNU 版本的 awk,功能最全,Linux 默认使用它。
  • 核心思想:将输入视为行(record)和字段(field),自动分割并处理

gawk 擅长:

  • 按字段(列)处理结构化文本(如 CSV、日志、/etc/passwd)
  • 条件过滤
  • 数值计算
  • 生成格式化报表
  • 它不是用来“编辑文件”的,而是用来“分析和转换数据流”的。

awk文件的每行数据都被称为记录,默认以空格或制表符为分隔符,每条记录被分成若干字段(列),awk每次从文件中读取一条记录。

sed命令常用于一整行的处理,而awk比较倾向于将一行分成多个“字段”然后再进行处理,也从不修改源文件

工作原理:

  逐行读取文本,默认以空格或tab键为分隔符进行分隔,将分隔所得的各个字段保存到内建变量中,并按模式或者条件执行编辑命令。

语法:

gawk [选项] '模式 {动作}' 文件
  • 模式(Pattern):决定对哪些行执行动作(可选)
  • 动作(Action):用 {} 包裹的操作(如打印、计算)
  • 若省略模式,则对所有行执行动作
  • 若省略动作,默认是 {print}
选项说明
-F 指定字段分隔符(默认空格或制表符),以每条记录中存在的字符作为分隔符
-v var=value 定义变量
-f script.awk 从文件读取 awk 脚本

awk常见的内建变量(可直接用):

记录(Record) = 一行(默认以换行符 \n 分隔)
字段(Field) = 一行中的列(默认以空格/制表符分隔)
变量全称默认值作用
$0 整行记录 当前处理的整行内容
$1, $2, ..., $NF 字段 第1、2、...、最后一个字段,当前处理行的第n个字段(第n列)。
FS Field Separator 空格或制表符 列分割符。指定每行文本的字段分隔符,默认为空格或制表位。与"-F"作用相同
OFS Output Field Separator 空格 输出字段分隔符(print 时字段间的分隔符)
NF Number of Fields 动态计算 当前行的字段总数
NR Number of Records 动态递增
当前处理的行的行号(序数)。
FNR File Number of Records 动态递增 当前文件的行号(多文件时重置)
FILENAME 当前文件名 正在处理的文件名
RS Record Separator \n 行分隔符,awk根据RS定义的行分隔符,把数据切割成多条记录。预设值是’\n’
ORS Output Record Separator \n 输出记录分隔符(print 后加的内容)

2、模式的 6 种主要写法(由简到繁)

1)正则表达式模式(最常用)

/.../ 包裹,匹配整行是否包含该模式。

/error/              // 行中包含 "error"
/^root/              // 行以 "root" 开头
/[0-9]{3}/           // 行包含连续3个数字(GNU awk 支持)
$1 ~ /admin/         // 第1列匹配 "admin"
$NF !~ /\.log$/      // 最后一列不以 .log 结尾

~ 表示“匹配正则”,!~ 表示“不匹配”

2)关系表达式模式

任何返回 true/false 的表达式都可作模式。

$3 > 1000           // 第3列数值 > 1000
NF == 5             // 字段数等于5
NR % 2 == 0         // 偶数行
$1 == "alice"       // 第1列等于 "alice"
length($0) > 80     // 行长度超过80字符

表达式为真(非0/非空)时,执行动作。

3)范围模式(行区间)

格式:起始模式, 结束模式

NR==5, NR==10           // 第5行到第10行
/^START/, /^END/        // 从包含 "START" 的行到包含 "END" 的行
$1=="user", $1=="end"   // 从 user 行到下一个 end 行

范围模式是“触发式”的,一旦开始,直到结束条件满足才停止。

4)布尔组合模式

&&(与)、||(或)、!(非)组合多个条件。

$3 > 100 && $4 < 50      // 第3列>100 且 第4列<50
/ERROR/ || /FATAL/       // 包含 ERROR 或 FATAL
!/^#/                    // 不以 # 开头(非注释行)

5)BEGIN 和 END 块

它们不匹配任何输入行,只控制执行时机。

  • BEGIN:处理第一行前执行(初始化)
  • END:处理完最后一行后执行(汇总)

语法:

BEGIN {
    // 初始化代码:设置变量、FS/OFS、打印表头等,BEGIN 中 没有 $0, $1, NR, FILENAME 等行相关变量(因为还没读文件)
}

// 主处理块(可选模式 + 动作)
/pattern/ {
    // 处理每一行
}

END {
    // 汇总代码:输出统计结果、总计、平均值等
}

执行顺序:

  1. 执行 BEGIN 块(只执行一次)
  2. 逐行读取文件,对每行执行主处理块
  3. 所有行处理完后,执行 END 块(只执行一次)

如:

1: awk '
2: BEGIN {           // 打印表头和分隔线
3:     printf "%-15s %8s %s\n", "Username", "UID", "Shell"
4:     print "----------------------------------------"
5: }
6: -F: {
7:     printf "%-15s %8d %s\n", $1, $3, $7
8: }
9: END {             // 打印底部横线,NR:已处理的总行数(即 /etc/passwd 的总行数)
10:    print "----------------------------------------"
11:    print "Total users:", NR
12: }
13: ' /etc/passwd

6)空模式(省略模式)

没有匹配模式

{ print $1 }   // 等价于:对所有行执行

 

如:awk对字段(列)的提取

  字段提取:提取文本中的一列数据并打印出来

  字段相关内置变量:

    $0 表示整行文本

    $1 表示文本行中的第一个数据字段

    $2 表示文本行中的第二个数据字段

    $N 表示文本行中的第N个数据字段

    $NF 表示文本行中的最后一个数据字段

// 打印第1列(用户名)
gawk '{print $1}' /etc/passwd

// 打印最后1列(shell)
gawk '{print $NF}' /etc/passwd

// 打印第1列和第3列
gawk '{print $1, $3}' /etc/passwd

///etc/passwd 用 : 分隔
gawk -F: '{print $1, $6}' /etc/passwd            // 指定分隔符(-F)
// 输出:用户名 + 家目录

// CSV 文件(逗号分隔)
gawk -F',' '{print $2}' data.csv

// 只处理包含 "root" 的行     
gawk '/root/ {print $0}' /etc/passwd            // 条件过滤(模式匹配)

// 第3列 > 1000 的用户(UID)
gawk -F: '$3 > 1000 {print $1}' /etc/passwd

// 行号在 5~10 之间
gawk 'NR>=5 && NR<=10 {print NR ": " $0}' file.txt

// 求第2列总和
gawk '{sum += $2} END {print "Total:", sum}' sales.txt      // END 块:所有行处理完后执行(用于汇总)

// 求平均值
gawk '{total += $1; count++} END {print "Avg:", total/count}' numbers.txt

// 最大值
gawk 'max=="" || $1>max {max=$1} END {print "Max:", max}' data.txt
// 格式化输出(printf)
gawk -F: '
BEGIN { printf "%-15s %8s %s\n", "User", "UID", "Home" }
      { printf "%-15s %8d %s\n", $1, $3, $6 }
' /etc/passwd

// 输出
User                UID Home
root               0 /root
john            1001 /home/john
greatwall@greatwall-pc:~/test$ awk -F' ' '{print $2}' employee.txt       // 以空格作为分隔符
Doe,CEO
Smith,IT
Reddy,Sysadmin
Ram,Developer
Miller,Sales
greatwall@greatwall-pc:~/test$ awk -F'0' '{print $2}' employee.txt    // 以数字0作为分隔符
1,John Doe,CEO
2,Jason Smith,IT Manager
3,Raj Reddy,Sysadmin
4,Anand Ram,Developer
5,Jane Miller,Sales Manager

 

posted @ 2025-11-18 09:13  chao_xiong  阅读(7)  评论(0)    收藏  举报