1. 为什么你需要掌握sed?
第一次接触sed时,我也觉得这个命令行工具看起来晦涩难懂。直到有次需要处理一个500MB的日志文件,用文本编辑器直接打开卡死,用Excel根本加载不了,这时候sed只用一行命令就搞定了数据清洗,我才真正体会到它的威力。
sed全称Stream EDitor(流编辑器),是Unix/Linux系统自带的文本处理神器。它最大的特点是逐行处理数据流,不会一次性加载整个文件,所以处理大文件时内存占用极低。我处理过2GB的CSV文件,sed依然游刃有余,这是GUI编辑器根本无法比拟的。
在实际工作中,这些场景你一定会用到sed:
- 批量修改服务器配置文件中的IP地址
- 从杂乱日志中提取关键错误信息
- 快速清理CSV文件中的异常格式
- 自动化脚本中的文本预处理
2. 基础语法:从hello world开始
2.1 基本命令结构
sed命令的标准格式就像下面这样:
sed [选项] '操作指令' 文件名最简单的例子,我们要把文本中的"world"替换为"sed":
echo "hello world" | sed 's/world/sed/' # 输出:hello sed这里用到了s替换命令,它的完整格式是s/旧内容/新内容/。记住这个模式,它能解决你80%的文本替换需求。
2.2 必须掌握的四个选项
刚开始用sed时,我建议先掌握这四个最常用的选项:
-n:静默模式,只输出处理过的行。配合
p命令可以精确控制输出内容:seq 1 5 | sed -n '3p' # 只输出第三行-i:直接修改文件内容(慎用!)。不加这个选项时sed只是输出处理结果,不会改原文件:
sed -i 's/old/new/g' file.txt # 真正修改文件-e:执行多条命令。比如先删除空行再替换内容:
sed -e '/^$/d' -e 's/foo/bar/' file.txt-r:使用扩展正则表达式。写复杂匹配规则时会方便很多:
echo "abc123" | sed -r 's/[a-z]+//' # 输出:123
3. 定位技巧:精确到行和字符
3.1 行号定位
处理日志文件时,经常需要针对特定行操作。sed支持多种定位方式:
sed '5d' file.txt # 删除第5行 sed '3,7s/old/new/' # 只修改3到7行 sed '$d' file.txt # 删除最后一行($表示末尾) sed '2~3d' access.log # 从第2行开始,每隔3行删除一行(适合采样)3.2 正则定位
更灵活的方式是用正则表达式定位:
sed '/error/d' app.log # 删除所有含error的行 sed '/^#/d' config.conf # 删除所有注释行(以#开头) sed '/start/,/end/d' # 删除从含"start"到含"end"的所有行我曾经用这个特性快速清理过nginx配置:
sed -i '/^$/d;/#.*$/d' nginx.conf # 删除空行和注释4. 高阶替换技巧
4.1 分组捕获与引用
这是sed最强大的功能之一。假设我们要把"2023-01-15"格式转为"01/15/2023":
echo "2023-01-15" | sed -r 's/([0-9]{4})-([0-9]{2})-([0-9]{2})/\2\/\3\/\1/'解释:
()捕获分组\1引用第一个分组-r启用扩展正则(支持+{}等元字符)
4.2 特殊替换技巧
大小写转换:
echo "Hello World" | sed 's/\(.*\)/\L\1/' # 转小写 echo "hello world" | sed 's/\(.*\)/\U\1/' # 转大写保留匹配部分:
echo "price: $99" | sed 's/price: \(\$[0-9]*\)/\1/' # 输出:$99非贪婪匹配(需要Perl模式):
echo "foo bar baz" | sed -E 's/(.*?)bar/\1BAR/' # 替换第一个bar
5. 实战案例解析
5.1 日志清洗实战
假设有个web日志片段:
127.0.0.1 - - [10/Oct/2023:13:55:36] "GET /api/user HTTP/1.1" 200 432 127.0.0.1 - - [10/Oct/2023:13:55:37] "POST /api/login HTTP/1.1" 200 342我们需要提取时间、方法和路径:
cat access.log | sed -E 's/.*\[(.*)\].*"(GET|POST) (\/[^ ]*).*/\1 \2 \3/'5.2 批量修改配置
有100台服务器的配置文件需要更新Redis地址:
sed -i 's/redis_host: .*/redis_host: 10.0.0.123/' /etc/app/*.conf5.3 CSV格式转换
原始数据:
name,age,gender John,25,M Lisa,30,F转为Markdown表格:
sed '1s/^/| /;1s/,/ | /g;1s/$/ |/;2,$s/^/| /;2,$s/,/ | /g;2,$s/$/ |/' data.csv6. 高级技巧与性能优化
6.1 多命令组合
用{}组合多个操作,比如删除空行并转换大小写:
sed '/^$/{d; s/.*/\L&/}' file.txt6.2 保持空间操作
sed有两个缓冲区:
- 模式空间:当前处理的行
- 保持空间:临时存储区
用h/H/g/G可以在两者间交换数据。比如实现行号标记:
sed = file.txt | sed 'N;s/\n/ /' # 给每行添加行号6.3 处理大文件技巧
禁用缓冲(GNU sed特有):
sed -u 's/foo/bar/' huge.log只处理匹配到的行:
sed '/pattern/!d' bigfile.txt > output.txt配合split分块处理:
split -l 1000000 bigfile.txt chunk_ for f in chunk_*; do sed -i 's/old/new/' "$f"; done
7. 常见坑与解决方案
MacOS与Linux的sed差异:
- Mac的sed需要加
''和-E替代-r
# Linux sed -i 's/foo/bar/' file # Mac sed -i '' -E 's/foo/bar/' file- Mac的sed需要加
特殊字符转义:
echo "/path/to/file" | sed 's/\//\\\//g' # 转义斜杠贪婪匹配问题:
echo "foo bar baz" | sed 's/foo.*baz/FOO BAR BAZ/' # 整行替换性能陷阱:
- 避免在循环中反复调用sed
- 复杂操作尽量用单个sed命令完成
8. 与其他工具配合
8.1 sed+awk黄金组合
提取nginx日志中的异常状态码:
awk '$9>400 {print}' access.log | sed -E 's/.*\[(.*)\].*/\1/'8.2 sed+grep管道处理
统计错误出现次数:
grep -i error app.log | sed 's/.*\(ERROR [a-z]*\).*/\1/' | sort | uniq -c8.3 在Shell脚本中的应用
自动化部署脚本示例:
#!/bin/bash OLD_IP="192.168.1.100" NEW_IP=$(curl -s ifconfig.me) sed -i "s/$OLD_IP/$NEW_IP/g" /etc/nginx/conf.d/*.conf systemctl reload nginx掌握sed后,你会发现很多原本需要写Python脚本处理的任务,用几行sed命令就能搞定。刚开始可能需要查手册,但经过20-30次实践后,这些命令就会变成你的肌肉记忆。建议保存这篇文章的代码片段,遇到实际问题时直接拿来修改使用。