Linux三剑客grep、sed、awk精要指南

Linux三剑客精要指南

适合有RHCE基础的运维工程师 | 测试环境:CentOS 7 / Debian / Ubuntu

快速对比

工具 核心功能 何时使用
grep 搜索/过滤 查找包含特定模式的行
sed 替换/编辑 文本替换、删除、插入
awk 分析/计算 复杂文本分析、格式化、统计

选择原则:grep查找 → sed替换 → awk计算


grep 文本搜索

核心选项(带英文全称)

-i (ignore-case)        # 忽略大小写
-v (invert-match)       # 反向匹配(不包含)
-n (line-number)        # 显示行号
-c (count)              # 统计匹配行数
-r (recursive)          # 递归搜索目录
-l (files-with-matches) # 只显示文件名
-A (after-context)      # 显示匹配行及后N行
-B (before-context)     # 显示匹配行及前N行
-C (context)            # 显示匹配行及前后N行
-E (extended-regexp)    # 使用扩展正则(egrep)
-o (only-matching)      # 只显示匹配部分
-w (word-regexp)        # 匹配整个单词
-q (quiet)              # 静默模式(脚本判断)

正则表达式速查

# 基本正则(BRE)
^       # 行首
$       # 行尾
.       # 任意字符
*       # 0次或多次
[]      # 字符集合
[^]     # 排除字符

# 扩展正则(ERE,使用-E)
+       # 1次或多次
?       # 0次或1次
|       # 或
()      # 分组
{n,m}   # 重复n到m次

实战案例

# 日志分析
grep -i "error" /var/log/messages                    # 查找错误
grep -C 3 "error" /var/log/messages | tail -20       # 带上下文
grep -o "ERROR\|WARNING" app.log | sort | uniq -c    # 统计错误类型

# 系统管理
grep -E ":[1-9][0-9]{3,}:" /etc/passwd               # 普通用户(UID>=1000)
grep -v "nologin\|false" /etc/passwd                 # 有登录shell的用户
netstat -tuln | grep LISTEN                          # 监听端口

# 配置文件
grep -Ev "^#|^$" /etc/ssh/sshd_config                # 有效配置(去注释和空行)
grep -rl "ServerName" /etc/apache2/                  # 查找包含配置的文件

# 代码审查
grep -rn "TODO\|FIXME" /path/to/project/             # 查找待办标记
grep -cvE "^$|^\s*#" script.py                       # 统计有效代码行数

sed 流编辑器

工作原理

1. 读取一行到"模式空间"(Pattern Space)
2. 执行sed命令
3. 输出模式空间内容(除非使用-n)
4. 清空模式空间,重复1-3

关键概念

  • 模式空间:主工作区,存放当前行
  • -n选项:禁用自动打印,只打印明确指定的行

核心选项

-n (quiet)              # 静默模式,不自动打印
-e (expression)         # 执行多个命令
-i (in-place)           # 直接修改文件
-i.bak                  # 修改前备份
-E (extended-regexp)    # 扩展正则

核心命令

# p (print) - 打印
sed -n '5p' file.txt                    # 打印第5行
sed -n '/pattern/p' file.txt            # 打印匹配行(类似grep)

# d (delete) - 删除
sed '/^$/d' file.txt                    # 删除空行
sed '/^#/d' file.txt                    # 删除注释行

# s (substitute) - 替换(最重要!)
sed 's/old/new/g' file.txt              # 全局替换
sed 's/old/new/gi' file.txt             # 忽略大小写
sed -n 's/old/new/p' file.txt           # 只显示被替换的行
sed 's|/usr/local|/opt|g' file.txt      # 使用|作为分隔符

# a (append) - 追加
sed '/pattern/a\new line' file.txt      # 在匹配行后添加

# i (insert) - 插入
sed '1i\#!/bin/bash' script.sh          # 在开头插入

# c (change) - 替换整行
sed '/pattern/c\new line' file.txt      # 替换匹配的行

地址定位

sed -n '5p' file.txt                    # 第5行
sed -n '5,10p' file.txt                 # 5到10行
sed -n '/start/,/end/p' file.txt        # 从start到end
sed -n '1~2p' file.txt                  # 奇数行
sed '/pattern/!d' file.txt              # 保留匹配行(删除不匹配)

实战案例

# 配置文件管理
sed -i.bak 's/^Port 22/Port 2222/' /etc/ssh/sshd_config
sed -i '/^SELINUX=/c\SELINUX=disabled' /etc/selinux/config
sed -i '/\[mysqld\]/a\max_connections=500' /etc/my.cnf

# 文本清理
sed 's/  \+/ /g' file.txt               # 多个空格→单个
sed 's/ \+$//' file.txt                 # 删除行尾空格
sed -e '/^$/d' -e '/^#/d' config.conf   # 删除空行和注释

# 数据转换
sed 's/,/\t/g' data.csv                 # CSV转TSV
sed -E 's/^([^ ]+) ([^ ]+)/\2 \1/' file.txt  # 交换列

awk 文本处理语言

工作原理

BEGIN块 → 逐行处理(读取→分割字段→匹配→执行) → END块

三大空间

  1. 字段空间:$0(整行), $1, $2..., $NF(最后字段)
  2. 变量空间:NR(行号), NF(字段数), FS(分隔符)
  3. 数组空间:关联数组(类似Python字典)

核心选项

-F (field-separator)    # 指定分隔符
-v (assign)             # 传递变量
-f (file)               # 使用脚本文件

# 示例
awk -F: '{print $1}' /etc/passwd        # 以冒号分隔
awk -v var=100 '{print $1+var}' file    # 传递变量

内置变量速查

$0          # 整行
$1, $2...   # 第1、2字段
$NF         # 最后字段
NF          # 字段数
NR          # 总行号
FNR         # 当前文件行号
FS/OFS      # 输入/输出分隔符

基础操作

# 打印字段
awk '{print $1, $3}' file.txt           # 打印第1和第3列
awk '{print $NF}' file.txt              # 打印最后一列

# 模式匹配
awk '/pattern/' file.txt                # 包含pattern的行
awk '$3 > 1000' /etc/passwd             # 第3字段>1000
awk '$1 ~ /^root/' /etc/passwd          # 第1字段匹配正则

# 条件判断
awk '{if ($3 > 1000) print $1}' /etc/passwd
awk '{print ($3 > 1000) ? "normal" : "system"}' /etc/passwd

# BEGIN和END
awk 'BEGIN {sum=0} {sum+=$1} END {print sum}' data.txt

数组(核心特性)

# 统计计数
awk '{count[$1]++} END {for(k in count) print k, count[k]}' file.txt

# 去重(经典技巧)
awk '!seen[$0]++' file.txt
# 解释:seen[$0]初始为0(假),!0为真,打印;seen[$0]++后为1,!1为假,不打印

# 词频统计
awk '{for(i=1;i<=NF;i++) words[$i]++} END {for(w in words) print w, words[w]}' file.txt

# 多维统计
awk -F: '{shells[$NF]++; uid_sum[$NF]+=$3} END {for(s in shells) print s, shells[s], uid_sum[s]}' /etc/passwd

# JOIN操作(关联两个文件)
awk 'NR==FNR {data[$1]=$2; next} {print $0, data[$1]}' file1.txt file2.txt

内置函数

# 字符串函数
length($1)              # 长度
substr($1, 1, 3)        # 提取子串
gsub(/old/, "new")      # 全局替换
tolower($1)             # 转小写
split($1, arr, "-")     # 分割字符串

# 数学函数
int($1)                 # 取整
sqrt($1)                # 平方根
rand()                  # 随机数[0,1)

实战案例

# 统计分析
awk '{sum+=$1} END {print sum/NR}' data.txt                    # 平均值
awk 'BEGIN{max=0} {if($1>max) max=$1} END {print max}' data.txt  # 最大值
awk '{ip[$1]++} END {for(i in ip) print i, ip[i]}' access.log | sort -k2 -rn | head -10  # TOP10 IP

# 日志分析
awk '{status[$9]++} END {for(s in status) print s, status[s]}' access.log  # HTTP状态码统计
awk '{sum+=$NF} END {print sum/NR}' response.log                # 平均响应时间
awk '$NF > 1 {print $0}' response.log                           # 响应时间>1秒

# 文本处理
awk 'NR%2==1' file.txt                                          # 奇数行
awk '{printf "%-20s %10s\n", $1, $2}' file.txt                  # 格式化输出
awk 'NR==FNR{a[$0];next} !($0 in a)' file1.txt file2.txt        # 文件差异

# 系统管理
ps aux | awk 'NR>1 {print $6, $11}' | sort -rn | head -10      # 内存占用TOP10
df -h | awk '$5+0 > 80 {print $0}'                              # 磁盘使用率>80%
awk -F: '{shells[$NF]++} END {for(s in shells) print s, shells[s]}' /etc/passwd  # shell统计

组合实战

组合技巧

# grep + awk:过滤后处理
grep "ERROR" app.log | awk '{print $1, $5}'

# sed + awk:清理后分析
sed '/^#/d; /^$/d' config.conf | awk '{print $1, $2}'

# 三剑客联合
grep "ERROR" app.log | sed 's/.*ERROR: //' | awk '{count[$1]++} END {for(e in count) print e, count[e]}'

Nginx日志分析

# 日志格式:IP - - [时间] "请求" 状态码 字节数

# TOP10 IP
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10

# 状态码统计
awk '{print $9}' access.log | sort | uniq -c | sort -rn

# TOP10 URL
awk '{print $7}' access.log | sort | uniq -c | sort -rn | head -10

# 每小时请求量
awk '{split($4,a,":"); print a[2]}' access.log | sort | uniq -c

# 404错误URL
awk '$9==404 {print $7}' access.log | sort | uniq -c | sort -rn

# 总流量(MB)
awk '{sum+=$10} END {print sum/1024/1024 " MB"}' access.log

系统性能分析

# CPU使用率
top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100-$1"%"}'

# 内存使用率
free -m | awk 'NR==2{printf "%.2f%%\n", $3*100/$2}'

# 磁盘使用率告警
df -h | awk '$5+0 > 80 {print $0}'

性能优化与最佳实践

性能对比

# 速度:grep > awk > sed
# 选择:简单搜索用grep,简单替换用sed,复杂处理用awk

优化技巧

# 1. 尽早退出
sed '100q' file.txt                     # 读100行后退出

# 2. 减少管道
# 慢:cat file | grep pattern | awk '{print $1}'
# 快:awk '/pattern/ {print $1}' file

# 3. 使用内置功能
# 慢:grep pattern file | wc -l
# 快:grep -c pattern file

# 4. 避免不必要的正则
# 慢:awk '$1 ~ /^test$/' file
# 快:awk '$1 == "test"' file

安全注意事项

# 1. 使用-i前先备份
sed -i.bak 's/old/new/g' file.txt

# 2. 先测试再应用
sed 's/old/new/g' file.txt | head      # 预览结果

# 3. 使用单引号避免shell解释
awk '{print $1}' file.txt              # 正确
awk "{print $1}" file.txt              # 错误($1被shell解释)

常见错误

# 1. sed -i在macOS上需要指定备份后缀
# Linux: sed -i 's/old/new/' file
# macOS: sed -i '' 's/old/new/' file
# 兼容: sed -i.bak 's/old/new/' file

# 2. awk分隔符需要引号
awk -F':' '{print $1}' file            # 正确
awk -F: '{print $1}' file              # 可能出错

# 3. 正则转义差异
# grep: 基本正则需要转义 \+, \?, \|
# grep -E/awk: 扩展正则不需要转义

学习路径

第1周:基础掌握

  • grep: -i, -v, -n, -r, -c, -A/-B/-C
  • sed: s命令(替换)、d命令(删除)
  • awk: 打印字段、简单过滤

第2-3周:进阶应用

  • 正则表达式(基本+扩展)
  • sed: 地址定位、多命令组合
  • awk: 变量、数组、条件循环

第4周+:实战提升

  • 编写日志分析脚本
  • 批量处理配置文件
  • 组合使用三剑客

核心要点

  1. grep:快速查找,简单高效
  2. sed:流式编辑,批量替换
  3. awk:强大灵活,复杂处理

使用原则:能用grep就不用awk,能用sed就不用awk,需要计算时用awk

持续学习:每天使用,形成肌肉记忆;遇到问题查阅笔记;记录常用命令


最后建议:不要试图一次性记住所有命令,在实际工作中遇到问题时查阅本笔记,通过反复使用来加深记忆。Linux三剑客的精髓在于实践!🚀