2708 words
14 minutes
grep,sed,awk详解

grep、sed、awk 详解:Unix 文本处理三剑客#

在 Unix/Linux 系统中,grep、sed、awk 被誉为”文本处理三剑客”。这三个工具虽然诞生于上世纪 70 年代,但至今仍是系统管理员、开发者和运维工程师的必备利器。它们组合使用可以完成几乎所有文本处理任务。本文将详细介绍这三个工具的核心概念、常用命令和实战技巧。

grep:模式搜索工具#

grep(Global Regular Expression Print)是最常用的文本搜索工具,它能够在文件中搜索符合指定模式的行,并将匹配的行输出到标准输出。

基本用法#

Terminal window
# 在文件中搜索包含 "error" 的行
grep "error" logfile.txt
# 搜索多个文件
grep "TODO" *.py *.js
# 递归搜索目录
grep -r "function" /path/to/code
# 显示行号
grep -n "import" main.py

常用选项#

grep 提供了丰富的命令行选项来控制搜索行为:

Terminal window
# -i:忽略大小写
grep -i "error" logfile.txt
# -v:反向匹配(不包含模式的行)
grep -v "^#" config.conf
# -c:只显示匹配行数
grep -c "print" script.py
# -l:只显示包含匹配内容的文件名
grep -l "TODO" *.py
# -r:递归搜索目录
grep -r "database" /path/to/project
# -n:显示行号
grep -n "def" main.py
# -A、-B、-C:显示上下文
grep -A 3 "error" logfile.txt # 显示匹配行后 3 行
grep -B 3 "error" logfile.txt # 显示匹配行前 3 行
grep -C 3 "error" logfile.txt # 显示匹配行前后各 3 行

正则表达式支持#

grep 支持两种正则表达式风格:

Terminal window
# 基本正则表达式(BRE)- 默认
grep "file\.txt" files.txt
# 扩展正则表达式(ERE)- 使用 -E 或 egrep
grep -E "error|warning|info" logfile.txt
# 常用正则表达式元字符
grep "^[0-9]" data.txt # 以数字开头
grep "test$" result.txt # 以 test 结尾
grep "a\{3,5\}" pattern.txt # 匹配 3-5 个 a(BRE)
grep -E "a{3,5}" pattern.txt # 匹配 3-5 个 a(ERE)
grep "[A-Z][a-z]+" names.txt # 大写字母开头后跟小写字母

实用示例#

Terminal window
# 查找进程
ps aux | grep python
# 查找空日志文件
find . -type f -empty | grep "\.log$"
# 统计代码行数
grep -c "" *.py | awk -F: '{sum+=$2} END {print sum}'
# 查找包含特定 IP 的访问日志
grep "192.168.1.100" access.log
# 查找以 # 开头的注释行
grep "^#" config.conf
# 查找不包含注释的配置行
grep -v "^#" config.conf | grep -v "^$"
# 查找 Git 仓库中的作者
git log | grep "Author:"

sed:流编辑器#

sed(Stream Editor)是一个强大的文本流编辑器,它能对输入流(文件或管道)执行基本的文本转换操作。sed 以行为单位处理文本,适合批量修改、删除、插入等操作。

基本语法#

Terminal window
sed [选项] '命令' 文件
sed [选项] -f 脚本文件 文件
# 常用选项
sed -n '10p' file.txt # 只显示第 10 行(-n 禁止默认输出)
sed -i.bak 's/old/new/g' file.txt # 直接修改文件并备份
sed -e 's/a/b/' -e 's/c/d/' file.txt # 执行多个命令

替换操作(s 命令)#

Terminal window
# 基本替换
sed 's/foo/bar/' file.txt # 将每行第一个 foo 替换为 bar
sed 's/foo/bar/g' file.txt # 将每行所有 foo 替换为 bar
# 使用分隔符(避免转义)
sed 's|/home/user|/home/newuser|' paths.txt
sed 's@http://@https://@g' urls.txt
# 删除匹配内容
sed 's/remove//g' file.txt
# 替换指定行
sed '10s/old/new/' file.txt # 只替换第 10 行
sed '/pattern/s/old/new/' file.txt # 只替换包含 pattern 的行
# 大小写转换
sed 's/\(.*\)/\L\1/' file.txt # 转换为小写
sed 's/\(.*\)/\U\1/' file.txt # 转换为大写

删除操作(d 命令)#

Terminal window
# 删除行
sed '5d' file.txt # 删除第 5 行
sed '/error/d' logfile.txt # 删除包含 error 的行
sed '/^$/d' file.txt # 删除空行
sed '5,10d' file.txt # 删除第 5-10 行
sed '/start/,/end/d' file.txt # 删除从 start 到 end 的所有行
sed '1d;$d' file.txt # 删除第一行和最后一行
# 删除注释行和空行
sed '/^#/d;/^$/d' config.conf
# 删除行尾空白
sed 's/[[:space:]]*$//' file.txt

插入和追加操作(i、a、c 命令)#

Terminal window
# 在指定行前插入
sed '5i\# This is a new line' file.txt
# 在指定行后追加
sed '5a\# This is an appended line' file.txt
# 在匹配行前插入
sed '/pattern/i\# Header before pattern' file.txt
# 替换整行
sed '5c\# This line replaces line 5' file.txt
# 文件头添加内容
sed '1i\#!/bin/bash\n# Author: Admin' script.sh

高级操作#

Terminal window
# 多行处理
sed 'N;s/\n/ /' file.txt # 合并连续两行
sed '/pattern/{N;s/\n/ /;}' file.txt
# 持久空间和模式空间
sed '/start/,/end/w output.txt' file.txt # 将匹配范围写入文件
# 条件处理
sed '/error/{s/error/ERROR/;w error.log;}' logfile.txt
# 引用匹配内容(反向引用)
sed 's/\([0-9]\{3\}\)\([0-9]\{4\}\)/\1-\2/' phone.txt
# 将 1234567 转换为 123-4567
# 执行外部命令
sed '10r /etc/hosts' file.txt # 在第 10 行后读取并插入文件内容

实用示例#

Terminal window
# 批量替换文件名中的空格为下划线
for file in *; do mv "$file" "$(echo $file | sed 's/ /_/g')"; done
# 移除 HTML 标签
sed 's/<[^>]*>//g' index.html
# 提取 IP 地址
sed -n 's/.*\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\).*/\1/p' access.log
# 格式化 JSON(简单美化)
cat data.json | sed 's/{/{\n/g;s/}/}\n/g;s/,/,\n/g'
# 在每个函数定义前添加注释
sed '/^def /i\# Function implementation' *.py
# 日志分析:提取错误信息
sed -n '/ERROR/p' application.log | sed 's/^.*ERROR: /Error: /'
# 配置文件:启用选项
sed -i 's/^#Port 22$/Port 22/' sshd_config
# CSV 处理:提取特定列
sed 's/,[^,]*$//' data.csv # 删除最后一列

awk:文本处理编程语言#

awk 是一种强大的文本处理编程语言,特别擅长处理结构化文本(如 CSV、日志文件)。它以行为单位处理文本,自动将每行分割成字段,并提供了完整的编程语言特性。

基本结构#

Terminal window
# 语法:awk 'pattern {action}' 文件
awk '/pattern/ {print}' file.txt
# 默认行为:打印匹配的整行
awk '/error/' logfile.txt
# 脚本格式
awk '
BEGIN {
# 初始化代码,执行一次
}
/pattern/ {
# 对匹配行执行的代码
}
{
# 对每一行执行的代码
}
END {
# 结束代码,执行一次
}
' file.txt

字段处理#

Terminal window
# 默认字段分隔符是空格和制表符
awk '{print $1}' file.txt # 打印第一个字段
awk '{print $1, $3}' file.txt # 打印第 1 和第 3 字段
awk '{print $NF}' file.txt # 打印最后一个字段
awk '{print $(NF-1)}' file.txt # 打印倒数第二个字段
# 指定字段分隔符
awk -F: '{print $1}' /etc/passwd # 以冒号为分隔符
awk -F, '{print $2}' data.csv # 以逗号为分隔符
awk 'BEGIN {FS="|"} {print $1}' data.txt
# 输出字段分隔符
awk 'BEGIN {FS=":"; OFS="-"} {print $1, $3}' /etc/passwd
# 记录分隔符
awk 'BEGIN {RS=";"} {print $1}' data.txt

内置变量#

Terminal window
# 常用内置变量
awk '{print NR, $0}' file.txt # NR:行号,$0:整行
awk '{print FNR, $0}' file1.txt file2.txt # FNR:当前文件行号
awk 'END {print NR}' file.txt # 总行数
awk '{print NF}' file.txt # 每行字段数
awk 'BEGIN {print FILENAME}' file.txt # 当前文件名
# 更多内置变量
awk '{print $0}' file.txt # $0:整行内容
awk '{if (NF > 5) print}' file.txt # NF:字段数量
awk 'BEGIN {FS=":"; OFS="\t"}' file.txt # FS:输入分隔符,OFS:输出分隔符
awk 'BEGIN {RS="\n\n"} {print}' file.txt # RS:记录分隔符
awk 'BEGIN {ORS="\n\n"} {print}' file.txt # ORS:输出记录分隔符

模式匹配#

Terminal window
# 正则表达式匹配
awk '/error/ {print}' logfile.txt
awk '!/error/ {print}' logfile.txt # 不匹配
awk '/^$/ {print NR}' file.txt # 空行的行号
# 字段匹配
awk '$3 == "admin"' users.txt
awk '$1 ~ /^[0-9]+$/' data.txt # 第一个字段是纯数字
awk '$1 !~ /^#/ {print}' config.conf # 不以 # 开头
# 比较操作
awk '$5 > 1000' sales.txt # 第 5 字段大于 1000
awk '$1 == "John" && $2 == "Doe"' users.txt
awk '$1 == "admin" || $1 == "root"' users.txt
# 范围模式
awk '/start/,/end/' file.txt # 从 start 到 end 的所有行
awk 'NR==10,NR==20' file.txt # 第 10-20 行

控制结构#

Terminal window
# if 语句
awk '{if ($1 > 100) print "High:", $1; else print "Low:", $1}' data.txt
# for 循环
awk '{for (i=1; i<=NF; i++) print $i}' file.txt
# while 循环
awk '{i=1; while (i<=NF) {print $i; i++}}' file.txt
# 数组
awk '{count[$1]++} END {for (name in count) print name, count[name]}' users.txt
# 函数
awk 'function sum(arr) {
total = 0
for (i in arr) total += arr[i]
return total
}
{for (i=1; i<=NF; i++) nums[i] = $i}
END {print sum(nums)}' numbers.txt

BEGIN 和 END 块#

Terminal window
# 计算列的平均值
awk 'BEGIN {sum=0; count=0}
{sum += $1; count++}
END {print "Average:", sum/count}' numbers.txt
# 统计文件信息
awk 'BEGIN {print "File Statistics:"}
END {print "Total lines:", NR; print "Total fields:", sum}' file.txt
# 格式化输出
awk 'BEGIN {printf "%-20s %10s %10s\n", "Name", "Age", "Salary"}
{printf "%-20s %10d %10.2f\n", $1, $2, $3}
END {print "--- End of report ---"}' employees.txt

实用示例#

Terminal window
# 统计每种状态的出现次数
awk '{count[$1]++} END {for (status in count) print status, count[status]}' status.log
# 计算日志中不同 IP 的访问次数
awk '{ip[$1]++} END {for (i in ip) print i, ip[i]}' access.log | sort -k2 -rn
# 提取 CSV 文件的特定列
awk -F, '{print $1, $3}' data.csv
# 计算数字列的总和
awk '{sum += $1} END {print sum}' numbers.txt
# 找出文件中最长的行
awk '{if (length($0) > max) {max = length($0); line = $0}} END {print line}' file.txt
# 日志分析:计算平均响应时间
awk '/response_time/ {sum += $3; count++} END {print "Avg:", sum/count}' server.log
# 转换为大写
awk '{print toupper($0)}' text.txt
# 去除重复行(类似 uniq)
awk '!seen[$0]++' file.txt
# 条件格式化
awk '{if ($3 > 90) printf "%s\t%s\tA\n", $1, $2;
else if ($3 > 80) printf "%s\t%s\tB\n", $1, $2;
else printf "%s\t%s\tC\n", $1, $2}' grades.txt
# 多文件处理
awk '{print FILENAME, NR, $0}' file1.txt file2.txt
# 时间戳转换
awk '{print strftime("%Y-%m-%d %H:%M:%S", $1)}' timestamps.txt

三剑客组合使用#

在实际工作中,grep、sed、awk 经常组合使用以完成复杂的文本处理任务:

Terminal window
# 查找并统计错误类型
grep "ERROR" application.log | awk '{print $4}' | sort | uniq -c
# 提取特定字段并进行转换
cat data.csv | grep "^2024" | awk -F, '{print $2}' | sed 's/,//g' | sort -n
# 日志分析管道
tail -f application.log | grep "ERROR" | awk '{print $1, $NF}' | while read ip message; do
echo "Error from $ip: $message"
done
# 复杂数据提取
curl -s https://api.example.com/data | grep -o '"name":"[^"]*"' | sed 's/"name":"//g' | sed 's/"//g'
# 配置文件处理
cat nginx.conf | grep server_name | awk '{print $2}' | sed 's/;//g'
# 日志统计报告
awk '/ERROR/{err++} /WARN/{warn++} /INFO/{info++}
END {printf "Errors: %d\nWarnings: %d\nInfo: %d\n", err, warn, info}' app.log

性能优化和最佳实践#

Terminal window
# 对于大文件,使用 grep 而不是 awk 进行简单匹配
grep "pattern" largefile.txt # 比 awk '/pattern/' 快
# 使用 head 和 head -n 进行预览
head -100 largefile.txt | awk '{...}'
# 使用 -i 选项时,注意性能影响
grep "pattern" file.txt # 比 grep -i 快
# 在 sed 中使用 -n 减少输出
sed -n '10,20p' file.txt # 只输出需要的行
# 在 awk 中使用数组统计时,注意内存使用
awk '{count[$1]++} END {...}' largefile.txt # 如果唯一键太多会占用大量内存
# 使用管道处理大文件
cat hugefile.txt | grep "pattern" | awk '{...}' > output.txt

总结#

grep、sed、awk 三个工具各有专长:

  • grep:快速搜索和过滤文本,擅长模式匹配
  • sed:流式编辑,擅长批量修改、删除、插入操作
  • awk:完整的编程语言,擅长结构化数据处理和复杂计算

掌握这三个工具不仅能提高工作效率,还能帮助理解 Unix 系统的设计哲学——“做好一件事”。在实际工作中,根据任务需求选择合适的工具,或者组合使用它们,可以大大简化文本处理工作。建议从简单的例子开始练习,逐步掌握更复杂的用法,最终能够熟练运用这三个工具解决实际问题。

grep,sed,awk详解
https://sgjki547.top/posts/grep-sed-awk/
Author
SGJki
Published at
2026-05-17
License
CC BY-NC-SA 4.0