Linux三剑客grep、sed、awk精要指南
- Linux系统
- 7小时前
- 7热度
- 0评论
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块
三大空间:
- 字段空间:$0(整行), $1, $2..., $NF(最后字段)
- 变量空间:NR(行号), NF(字段数), FS(分隔符)
- 数组空间:关联数组(类似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周+:实战提升
- 编写日志分析脚本
- 批量处理配置文件
- 组合使用三剑客
核心要点
- grep:快速查找,简单高效
- sed:流式编辑,批量替换
- awk:强大灵活,复杂处理
使用原则:能用grep就不用awk,能用sed就不用awk,需要计算时用awk
持续学习:每天使用,形成肌肉记忆;遇到问题查阅笔记;记录常用命令
最后建议:不要试图一次性记住所有命令,在实际工作中遇到问题时查阅本笔记,通过反复使用来加深记忆。Linux三剑客的精髓在于实践!🚀