前言
在日常的 Linux 运维和开发工作中,我们经常需要对文本文件进行批量编辑、替换、删除等操作。虽然可以用 Vim 手动编辑,但当面对大文件或需要自动化处理时,sed 就是你的最佳选择。
sed 是 Stream Editor(流编辑器)的缩写,它可以在不打开文件的情况下,对文本进行高效的编辑处理。本文将带你从零开始,掌握 sed 的核心用法。
一、sed 是什么?
sed 是一个非交互式文本编辑器,它按照预设的规则逐行处理文本,适用于:
- 批量替换文件中的字符串
- 删除或提取特定行
- 插入、追加、修改文本内容
- 自动化脚本中的文本处理
基本语法
sed [选项] '命令' 文件名
常用选项
| 选项 | 说明 |
|---|---|
-i | 直接修改原文件(危险操作,建议先备份) |
-e | 执行多个 sed 命令 |
-n | 静默模式,只打印被处理的行 |
-r 或 -E | 使用扩展正则表达式 |
二、核心概念:地址定位
sed 的核心是 “找位置 → 做操作”。你需要告诉 sed 要处理哪些行(地址),然后执行什么操作(命令)。
地址定位方式
# 1. 不指定地址:处理所有行 sed 'd' file.txt # 删除所有行 # 2. 指定行号 sed '3d' file.txt # 删除第3行 sed '5,10d' file.txt # 删除第5-10行 # 3. 使用正则匹配 sed '/error/d' file.txt # 删除包含error的行 # 4. 从匹配行到文件末尾 sed '/start/,$d' file.txt # 5. 使用行号与正则混合 sed '5,/error/d' file.txt # 从第5行删到匹配error的行
取反操作 !
# 不删除第3行(即保留第3行,删除其他所有行) sed '3!d' file.txt # 删除不包含error的行 sed '/error/!d' file.txt
三、增删改查:sed 四大核心操作
1. 删除(d)
# 删除空行 sed '/^$/d' file.txt # 删除注释行(以#开头) sed '/^#/d' file.txt # 删除第2行到最后一行 sed '2,$d' file.txt # 删除最后一行 sed '$d' file.txt # 删除包含特定字符串的行 sed '/delete_this/d' file.txt # 删除奇数行 sed '1~2d' file.txt # 1,3,5...行
2. 替换(s///)
这是 sed 最常用的功能。
# 基本替换:将第一个apple替换为orange sed 's/apple/orange/' file.txt # 全局替换(所有匹配) sed 's/apple/orange/g' file.txt # 只替换第2个匹配 sed 's/apple/orange/2' file.txt # 替换第3行到第5行的内容 sed '3,5 s/apple/orange/g' file.txt # 使用其他分隔符(当路径包含/时) sed 's|/usr/bin|/usr/local/bin|g' file.txt sed 's#/usr/bin#/usr/local/bin#g' file.txt # 忽略大小写 sed 's/apple/orange/gi' file.txt # 替换并打印修改的行 sed -n 's/apple/orange/gp' file.txt
高级替换:使用分组
# 交换前两个单词 echo "John Doe" | sed 's/\([^ ]*\) \(.*\)/\2 \1/' # 输出: Doe John # 提取IP地址 echo "IP: 192.168.1.1" | sed 's/.*: \([0-9.]*\)/\1/' # 输出: 192.168.1.1 # 添加HTML标签 sed 's/.*/<p>&<\/p>/' file.txt # &代表匹配的整个内容
3. 打印(p)与静默模式(-n)
# 打印第5行
sed -n '5p' file.txt
# 打印匹配的行
sed -n '/error/p' file.txt
# 打印第10行到第20行
sed -n '10,20p' file.txt
# 打印行号
sed -n '=; p' file.txt # 先打印行号,再打印内容
# 打印匹配行的行号和内容
sed -n '/error/{=;p}' file.txt
4. 插入、追加、修改
# i: 在匹配行之前插入 sed '/pattern/i\这是插入的新行' file.txt # a: 在匹配行之后追加 sed '/pattern/a\这是追加的新行' file.txt # c: 替换整行 sed '/pattern/c\这行被替换了' file.txt # 在第3行前插入 sed '3i\插入的内容' file.txt # 在第3行后追加 sed '3a\追加的内容' file.txt
四、实战案例
案例1:批量修改配置文件
# 将nginx配置中的端口从8080改为80 sed -i 's/listen 8080;/listen 80;/g' /etc/nginx/sites-available/default # 注释掉包含特定配置的行 sed -i '/^sendfile on;/s/^/#/' /etc/nginx/nginx.conf
案例2:清理日志文件
# 删除DEBUG级别的日志 sed -i '/DEBUG/d' app.log # 只保留最近7天的日志(假设日志格式包含日期2025-01-01) sed -n '/2025-05-1[6-9]/,$p' app.log
案例3:CSV文件处理
# 替换CSV中的空字段为NULL sed -i 's/,,/,NULL,/g' data.csv sed -i 's/,$/,NULL/' data.csv # 删除CSV表头 sed -i '1d' data.csv
案例4:代码批量修改
# 将所有Python print改为logging sed -i 's/print(/logging.info(/g' *.py # 添加版权信息到文件开头 sed -i '1i\# Copyright 2025 My Company' *.py
案例5:从HTML中提取内容
# 提取所有title标签内容
sed -n 's/.*<title>\(.*\)<\/title>.*/\1/p' index.html
# 删除所有HTML标签
sed 's/<[^>]*>//g' page.html
案例6:给配置文件每行添加引号
# 每行添加双引号 sed 's/^/"/; s/$/"/' config.txt # 输出示例: # "line1" # "line2"
案例7:生成SQL插入语句
# 将数据文件转换为SQL
sed "s/^/INSERT INTO users VALUES ('/; s/$/');/" data.txt
# data.txt内容:
# john,25
# mary,30
# 输出:
# INSERT INTO users VALUES ('john,25');
# INSERT INTO users VALUES ('mary,30');
案例8:Markdown转HTML
# 给每行添加HTML段落标签 sed 's/^/<p>/; s/$/<\/p>/' article.txt
案例9:日志添加时间戳
# 在每行行首添加当前时间 sed "s/^/$(date '+%Y-%m-%d %H:%M:%S') /" app.log
案例10:CSV转JSON(简化版)
# 给CSV每行添加JSON格式
sed 's/^/{"data": "/; s/$/"}/' data.csv
五、多命令组合
使用 -e 选项
# 删除空行和注释行 sed -e '/^$/d' -e '/^#/d' file.txt # 等价于 sed '/^$/d; /^#/d' file.txt
使用分号 ;
# 替换多个字符串 sed 's/cat/dog/g; s/white/black/g' file.txt # 先替换再删除空行 sed 's/foo/bar/g; /^$/d' file.txt
使用花括号 {} 对同一地址执行多个命令
# 对第10-20行执行多个操作
sed '10,20{
s/foo/bar/g
s/abc/xyz/g
/^$/d
}' file.txt
六、sed 脚本文件
当命令复杂时,可以写成脚本文件。
bash
# 创建脚本 script.sed cat > script.sed << 'EOF' #!/usr/bin/sed -f # 删除空行 /^$/d # 替换字符串 s/old/new/g # 在文件末尾添加结束标记 $a\# End of file EOF # 执行脚本 sed -f script.sed input.txt > output.txt
七、常见陷阱与注意事项
1. -i 选项的风险
# 危险:直接修改原文件且无法恢复 sed -i 's/old/new/g' important.conf # 安全做法:先备份 sed -i.bak 's/old/new/g' important.conf # 预览修改(不实际修改) sed 's/old/new/g' important.conf | less
2. 特殊字符需要转义
需要转义的字符:. * [ ^ $ \ / ( )
# 错误:. 被解释为正则 echo "192.168.1.1" | sed 's/192.168.1.1/IP/g' # 不工作 # 正确:转义点号 echo "192.168.1.1" | sed 's/192\.168\.1\.1/IP/g' # 或者使用其他分隔符避免转义/ echo "/usr/local/bin" | sed 's|/usr/local/bin|/opt/bin|'
八、sed 与其他命令的配合
与 grep 配合
# 先过滤再编辑 grep 'ERROR' app.log | sed 's/ERROR/WARNING/g' # 等价于 sed -n '/ERROR/s/ERROR/WARNING/p' app.log
与 awk 配合
# awk处理列,sed处理格式
awk '{print $1, $3}' data.txt | sed 's/^/Record: /'
与管道组合
# 实时监控日志并脱敏
tail -f app.log | sed 's/[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}/DATE/g'
# 格式化命令输出
ps aux | sed -n '2,$p' | sed 's/\([^ ]*\).*/\1/' # 提取第一列
九、快速参考卡
| 操作 | 命令示例 |
|---|---|
| 删除空行 | sed '/^$/d' |
| 删除第5行 | sed '5d' |
| 删除5-10行 | sed '5,10d' |
| 删除包含pattern的行 | sed '/pattern/d' |
| 全局替换 | sed 's/old/new/g' |
| 只替换第2个匹配 | sed 's/old/new/2' |
| 打印第5行 | sed -n '5p' |
| 打印匹配行 | sed -n '/pattern/p' |
| 在第3行前插入 | sed '3i\新行' |
| 在第3行后追加 | sed '3a\新行' |
| 替换整行 | sed '/pattern/c\新内容' |
| 多重命令 | sed -e 'cmd1' -e 'cmd2' |
十、进阶学习资源
- 正则表达式:sed 的灵魂,建议深入学习
- sed one-liners:网上有很多经典的单行脚本
- info sed:完整的 sed 官方文档
结语
sed 是每个 Linux 用户都应该掌握的工具。虽然它的语法看起来有些晦涩,但核心就是 “找位置,做操作”。建议你:
- 先在测试文件上练习
- 多用
-n和p预览结果 - 重要操作前先用
-i.bak备份
掌握 sed 后,你会发现文本处理效率提升 10 倍以上。动手试试吧!


发表回复