sed(stream editor)是一种非交互式的文本处理工具,它逐行读取输入流,按照给定的指令修改内容,然后把处理后的结果输出。因为不需要打开完整的可视界面,sed 非常适合在管道线里与其他命令配合,批量处理日志、配置文件和大批量文本。
1. 基本工作方式
sed 对每一行文本依次执行“匹配地址 → 执行命令”的流程。如果地址匹配成功,相应命令就会作用于该行;否则原样输出(或者根据 -n 选项禁止默认输出)。常用的使用形式是:
sed [选项] '地址命令' 文件...
sed [选项] -e '命令1' -e '命令2' 文件...
如果省略文件,sed 会从标准输入读取数据,这样就可以直接通过管道接收上游命令的输出。
2. 常用选项(务实版)
-n:禁止默认输出,只有经过明确打印命令(p)的行才会被输出。这在只想提取特定行时极其常用。-e:指定多条编辑命令,后接命令字符串。-i:直接修改原文件(谨慎使用)。GNUsed下若在-i后添加扩展名,例如-i.bak,则会在修改前创建备份文件(如原文件.bak)。-r或-E:启用扩展正则表达式,使+、?、()、{}等符号默认具有正则含义,而不用大量加反斜线。
3. 地址与命令的组合
地址可以是行号、正则表达式或范围。命令则有 s(替换)、d(删除)、p(打印)、a(后插)、i(前插)、c(替换整行)等。最核心的用法是替换和选择性输出。
3.1 行号定位
- 输出文件第 3 行到第 8 行:
sed -n '3,8p' log.txt
- 从第 5 行到文件末尾全部删除(不输出):
sed '5,$d' file.txt
3.2 正则定位
- 删除所有包含
DEBUG的行:
sed '/DEBUG/d' app.log
- 输出从第一个匹配
START的行到第一个匹配END的行之间的内容:
sed -n '/START/,/END/p' data.txt
4. 替换命令 s:核心竞争力
s 命令的格式为 s/正则/替换内容/修饰符。分隔符不仅限于 /,也可以用 #、| 等减少转义麻烦。
- 简单替换:把每个
apple替换为orange
sed 's/apple/orange/' fruits.txt
注意每行只替换第一次出现。要全局替换加 g 修饰符:
sed 's/apple/orange/g' fruits.txt
- 使用正则捕获组:将
key=value格式转换为key: value
sed 's/\(.*\)=\(.*\)/\1: \2/' config.txt
若用了 -E(即 -r),写法更清晰:
sed -E 's/(.*)=(.*)/\1: \2/' config.txt
- 选择性替换:只对匹配
server的行进行替换
sed '/server/s/80/443/' nginx.conf
- 使用不同分隔符:替换路径时用
#避免转义
sed 's#/home/user#/opt/app#' paths.txt
- 大小写不敏感替换:加上
i修饰符
sed 's/error/ERROR/gi' log.txt
5. 实战场景
场景一:快速修改配置文件
要关闭 SSH 的密码认证,需把 #PasswordAuthentication yes 或 PasswordAuthentication yes 改为 PasswordAuthentication no,并去掉行首注释:
sed -E 's/^#?(PasswordAuthentication).*/\1 no/' /etc/ssh/sshd_config
确认无误后加上 -i 直接写入文件:
sudo sed -i -E 's/^#?(PasswordAuthentication).*/\1 no/' /etc/ssh/sshd_config
场景二:清理日志中的 IP 地址
只提取每行日志中第一个出现的 IP:
sed -n 's/.*\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\).*/\1/p' access.log
若使用 -E,正则可以写得简短:
sed -nE 's/.*([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/\1/p' access.log
场景三:批量重命名文件(生成脚本)
用 sed 生成重命名命令,检查无误后执行:
ls *.txt | sed 's/\(.*\)\.txt/mv \1.txt \1.md/'
输出类似 mv note.txt note.md 的行,确认后通过 sh 执行:
ls *.txt | sed 's/\(.*\)\.txt/mv \1.txt \1.md/' | sh
这是一种安全做法——先看到生成的命令,再决定是否提交执行。
场景四:多行插入与追加
在某行下追加一行:
sed '/\[mysqld\]/a max_connections = 500' my.cnf
在某行前插入一行:
sed '/\[mysqld\]/i # 数据库配置' my.cnf
6. 与其它工具的组合
sed 生来就在管道中发挥作用。例如结合 find 和 xargs 批量替换多个文件中的字符串:
find . -name "*.html" -print0 | xargs -0 sed -i 's/old-domain.com/new-domain.com/g'
或者从 grep 的输出中筛选内容并进一步处理:
grep 'ERROR' app.log | sed 's/.*msg="\([^"]*\)".*/\1/'
先通过 grep 过滤包含 ERROR 的行,再用 sed 提取引号内的错误描述。
7. 实用要点
sed默认将结果输出到标准输出(屏幕),不会改动原文件,安全试验时可去掉-i先预览。- 使用
-i要格外小心,尤其是与*通配符联用时,建议先备份或使用-i.bak。 sed支持在脚本中使用-f选项从文件读取多条编辑命令,适合复杂、可复用的编辑流程。- 当一行内有多处替换需求时,务必记得加
g标记,否则只会替换第一个匹配。 - 熟练掌握
sed后,许多原本需要打开编辑器才能完成的小修改(如去除行尾空格、统一缩进、删除空行等)都可以在命令行瞬间完成,效率显著提升。
sed 的哲学和 Linux 其他核心工具一致:不追求一次性解决所有问题,而是做好流式文本替换这件事,让你能把它作为构建块嵌入到更大的自动化流程中。