飞翔飞翔
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • 学习路径
  • 基础入门

    • Linux 命令概述与环境准备
    • 文件与目录操作(上):ls、cd、pwd
    • 文件与目录操作(下):cat、touch、mkdir、rm、cp、mv
    • 获取帮助与基础工具:man、help、clear、exit、sudo
  • 文件权限

    • 文件权限管理:chmod、chown
  • 系统与监控

    • 进程管理与系统监控:ps、top、kill、df、du、free
    • 用户与环境:whoami、id、env、echo、history
  • 网络命令

    • 网络诊断(上):ping、curl、wget
    • 网络诊断(下):netstat、ss、ip
    • 网络抓包与高级工具:traceroute、tcpdump、nc
    • DNS 与防火墙:nslookup、dig、iptables
  • 文本处理

    • 文本搜索:grep
    • 文本处理(上):awk
    • 文本处理(下):sed
    • 文本排序与统计:sort、uniq、wc
    • 文件查看与查找:head、tail、cut、find
    • 归档压缩与管道组合:tar、gzip、xargs
  • 开发工具

    • 开发工具链(上):gcc、make
    • 开发工具链(下):gdb、time
    • 版本控制:git
    • 远程操作:ssh、scp
    • 编辑器:vim、nano
  • Shell 编程

    • Shell 编程基础(上):变量、管道、重定向
    • Shell 编程基础(下):条件、循环、函数
  • 综合实战

    • 综合实战:日志分析

文本处理(上):awk

awk 核心定位

awk 是按列处理文本的利器。它把每一行按分隔符切分成多个字段(Field),然后对指定字段进行操作。

基础语法

awk 'pattern { action }' file
  • pattern:匹配条件(可选)
  • action:对匹配行执行的操作
  • file:输入文件
# 打印文件的每一行(等同于 cat)
awk '{print}' file.txt

# 打印第 1 列
awk '{print $1}' file.txt

# 打印第 1 列和第 3 列
awk '{print $1, $3}' file.txt

# 打印整行($0 表示整行)
awk '{print $0}' file.txt

# 打印行号(NR = Number of Record)
awk '{print NR, $0}' file.txt

# 打印总行数
awk 'END {print NR}' file.txt

分隔符处理

# 指定分隔符(-F field-separator)
awk -F: '{print $1}' /etc/passwd      # 以 : 分隔,打印用户名
awk -F, '{print $2}' data.csv         # 以 , 分隔,打印第 2 列

# 多个分隔符
awk -F'[:,]' '{print $1}' file.txt    # 以 : 或 , 分隔

# 正则分隔符
awk -F'[ ]+' '{print $1}' file.txt    # 一个或多个空格

/etc/passwd 结构示例

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
字段含义
$1用户名
$2密码占位符(x)
$3UID
$4GID
$5用户全名/注释
$6家目录
$7默认 Shell
# 提取用户名和 Shell
awk -F: '{print "User:", $1, "Shell:", $7}' /etc/passwd

# 输出:
# User: root Shell: /bin/bash
# User: daemon Shell: /usr/sbin/nologin

条件过滤

# 打印 UID >= 1000 的普通用户
awk -F: '$3 >= 1000 {print $1, $3}' /etc/passwd

# 打印 Shell 是 /bin/bash 的用户
awk -F: '$7 == "/bin/bash" {print $1}' /etc/passwd

# 打印包含 "root" 的行
awk '/root/' /etc/passwd

# 打印第 3 列大于 50 的行
awk '$3 > 50 {print $1, $3}' data.txt

# 匹配正则表达式
awk '$1 ~ /^[A-Z]/ {print $1}' file.txt    # 第 1 列以大写字母开头

内置变量

变量含义示例
$0整行内容awk '{print $0}'
$1-$n第 n 个字段awk '{print $1}'
NF字段数量(Number of Fields)awk '{print NF}'
NR行号(Number of Record)awk '{print NR, $0}'
FS输入分隔符(Field Separator)awk 'BEGIN{FS=":"}'
OFS输出分隔符(Output FS)awk 'BEGIN{OFS=","}'
RS记录分隔符(Record Separator,默认换行)awk 'BEGIN{RS=""}'
ORS输出记录分隔符awk 'BEGIN{ORS="\n\n"}'
FILENAME当前文件名awk '{print FILENAME}'
# 打印每行的字段数
awk '{print NR, NF, $0}' file.txt

# 打印最后一列(用 NF)
awk '{print $NF}' file.txt

# 自定义输出格式
awk 'BEGIN{OFS=" | "} {print $1, $2, $3}' file.txt

BEGIN 和 END 块

# BEGIN:处理文件前执行
# END:处理完所有行后执行

# 统计文件行数、单词数、字符数(简化版 wc)
awk 'BEGIN{print "开始统计..."}
     {lines++; words+=NF; chars+=length($0)}
     END{print "行数:", lines
         print "单词数:", words
         print "字符数:", chars}' file.txt

# 计算第 2 列的平均值
awk '{sum+=$2; count++} END{print "平均值:", sum/count}' data.txt

# 找出第 3 列的最大值
awk 'NR==1{max=$3} $3>max{max=$3} END{print "最大值:", max}' data.txt

实战场景

场景 1:分析 Nginx 访问日志

# 日志格式:IP - - [时间] "请求方法 URL 协议" 状态码 大小 "Referer" "User-Agent"
# 示例:192.168.1.1 - - [15/Jan/2024:10:00:00 +0800] "GET /index.html HTTP/1.1" 200 1234 "-" "Mozilla/5.0"

# 提取 IP 和状态码
awk '{print $1, $9}' access.log

# 统计每个 IP 的访问次数
awk '{count[$1]++} END{for(ip in count) print count[ip], ip}' access.log | sort -rn

# 统计每个状态码的数量
awk '{code[$9]++} END{for(c in code) print code[c], c}' access.log

# 计算平均响应大小(第 10 列是响应大小)
awk '{sum+=$10; count++} END{print "平均大小:", sum/count, "字节"}' access.log

场景 2:处理 CSV 文件

# data.csv:
# name,age,salary
# Alice,25,8000
# Bob,30,12000
# Carol,28,9500

# 打印姓名和工资
awk -F, 'NR>1 {print $1, $3}' data.csv

# 计算平均工资(跳过标题行)
awk -F, 'NR>1 {sum+=$3; count++} END{print "平均工资:", sum/count}' data.csv

# 找出工资最高的人
awk -F, 'NR>1 && $3>max{max=$3; name=$1} END{print "最高工资:", name, max}' data.csv

本篇小结

  • awk 是按列处理文本的核心工具,默认以空格/制表符分隔
  • 基础语法:awk 'pattern {action}' file
  • -F 指定分隔符,-F: 以冒号分隔,-F, 以逗号分隔
  • $0 整行,$1-$n 第 n 列,$NF 最后一列
  • NR 行号,NF 字段数,FS/OFS 输入/输出分隔符
  • BEGIN 块:处理前初始化;END 块:处理后统计输出
  • 数组统计:count[$1]++,END{for(x in count) print count[x], x}

动手实践

  1. 解析 /etc/passwd:

    awk -F: '{print "用户:", $1, "UID:", $3, "Shell:", $7}' /etc/passwd
    awk -F: '$3 >= 1000 {print $1, $3}' /etc/passwd
    
  2. 创建测试数据并处理:

    cat > scores.txt
    Alice 85 90 78
    Bob 92 88 95
    Carol 78 82 80
    # Ctrl+D
    
    # 计算每人总分和平均
    awk '{sum=$2+$3+$4; avg=sum/3; print $1, "总分:", sum, "平均:", avg}' scores.txt
    
    # 找出最高分
    awk '{sum=$2+$3+$4; if(sum>max){max=sum; name=$1}} END{print "最高分:", name, max}' scores.txt
    
  3. 统计单词频率:

    awk '{for(i=1;i<=NF;i++) count[$i]++} END{for(w in count) print count[w], w}' scores.txt | sort -rn
    
  4. 处理 CSV:

    cat > shop.csv
    item,price,quantity
    apple,5.5,100
    banana,3.2,200
    orange,4.8,150
    # Ctrl+D
    
    awk -F, 'NR>1 {print $1, "总价:", $2*$3}' shop.csv
    awk -F, 'NR>1 {total+=$2*$3} END{print "总销售额:", total}' shop.csv
    
  5. 思考:awk '{print $NF}' 和 awk '{print $(NF-1)} 分别输出什么?如果一行有 5 个字段,NF 的值是多少?

上一页
文本搜索:grep
下一页
文本处理(下):sed