用法简介:

1
sed [OPTIONS]... {script-only-if-no-input} [FILE...]

sed 是一个流编辑器(stream editor),逐行处理输入并按脚本进行转换。脚本可以直接在命令行用 -e 指定,或用 -f 从文件读取。

常用选项:

1
2
3
4
5
6
-e SCRIPT     # 指定脚本
-f SCRIPTFILE # 从脚本文件读取命令
-n # 不自动打印每行,常与 p 一起使用以选择性打印
-i[SUFFIX] # 原地编辑文件,可选备份后缀(GNU/BSD 语法略有不同)
-r / -E # 启用扩展正则(GNU: -r,BSD/macOS: -E)
--help

地址(Addressing)概念:

  • 单行地址:N(行号),$(最后一行),/regex/(匹配正则的行)
  • 范围:addr1,addr2 表示从 addr1 到 addr2 的连续行
  • 步进:firststep(GNU 扩展),例如 12 表示奇数行

常用命令(单字母):

  • p :打印当前模式空间(配合 -n 使用)
  • d :删除当前行(即跳过打印,继续下一行)
  • s/RE/REPL/FLAGS:替换(常用 FLAGS:g 全局,p 打印,NUMBER 仅替换第 N 次,I 或 i 可用于忽略大小写在部分实现中)
  • i\ TEXT :在当前地址之前插入文本(脚本中换行写法)
  • a\ TEXT :在当前地址之后追加文本
  • c\ TEXT :替换指定行或范围为 TEXT
  • y/abc/xyz/:字符逐个转换(类似 tr)
  • = :输出当前行号
  • q :退出(立即停止处理)
  • h, H, g, G, x:hold space(保持空间)相关命令,用于跨行处理

替换详解(s///):

  • 基本:s/old/new/ # 替换第一次出现
  • 全局:s/old/new/g # 替换行内所有匹配
  • 打印匹配:sed -n ‘s/old/new/p’
  • 使用不同分隔符(避免转义):s|/path/old|/path/new|g
  • 捕获与反向引用:s/(foo)bar/\1baz/ 或 POSIX 风格 \1(扩展正则可用括号)
  • 在替换文本中使用 & 表示整个匹配,\1、\2 表示分组

原地编辑(-i):

  • GNU: sed -i.bak ‘s/a/b/g’ file # 备份为 file.bak
  • BSD/macOS: sed -i ‘’ ‘s/a/b/g’ file

示例(短而常用):

  • 简单替换并打印结果:

    1
    sed 's/foo/bar/g' file.txt
  • 仅打印包含替换后的行:

    1
    sed -n 's/foo/bar/p' file.txt
  • 原地替换并备份:

    1
    sed -i.bak 's/oldname/newname/g' *.conf
  • 删除匹配的行:

    1
    sed '/^#/d' file.conf           # 删除注释行
  • 删除行范围:

    1
    sed '10,20d' file.txt           # 删除第 10 到 20 行
  • 在匹配行之前插入一行:

    1
    2
    sed '/pattern/i\
    Inserted line' file.txt
  • 在匹配行之后追加一行:

    1
    2
    sed '/pattern/a\
    Appended line' file.txt
  • 列出行号与内容:

    1
    2
    3
    sed -n '=' file.txt | sed -n 'N; s/\n/: /; p'  # 将行号与行合并为 "번호: 内容"
    # 或者更直接:
    nl -ba file.txt

脚本文件示例(script.sed):

1
2
3
4
# script.sed
/^#/d
s/foo/bar/g
28,30d

调用:

1
sed -f script.sed input.txt

多行与缓冲区(进阶):

  • N:读取下一行并追加到模式空间(在模式空间中存在换行符)
  • P:打印模式空间到第一个换行前的部分
  • D:删除第一个换行前的部分并重复循环(用于循环处理多行)
  • h/H、g/G、x:在模式空间与保持空间间交换,用于跨行上下文处理
    示例:合并连续行中的模式
    1
    2
    # 将 "foo" 后紧接换行的 "bar" 合并为 "foo bar"
    sed -n 'N; s/foo\nbar/foo bar/; p' file

与 grep/awk/perl 的选择:

  • sed 擅长逐行的流式文本替换与简单变换;
  • awk 更适合字段/记录级别的处理与数据抽取;
  • perl/python 在复杂正则、编码处理或更强逻辑时更灵活;
  • 对于速度与递归搜索,可使用 ripgrep/ag 等工具(针对搜索,非替换)。

注意事项与兼容性:

  • 不同 sed 实现(GNU sed、BSD sed/macOS)在 -r/-E、-i 参数和扩展标志上有差异,请根据目标平台测试脚本;
  • 正则语法(BRE vs ERE vs PCRE)差别会影响分组与特殊语法;必要时在脚本头注明预期环境;
  • 对二进制文件谨慎操作,原地替换前最好有备份或版本控制。

常见示例集:

1
2
3
4
5
6
7
8
# 将 files 中所有 .conf 文件的 key1 值改为 newvalue(备份原文件)
sed -i.bak 's/^key1=.*/key1=newvalue/' *.conf

# 递归结合 find(小心空格文件名)
find . -name '*.txt' -print0 | xargs -0 sed -i 's/old/new/g'

# 提取以 ERROR 开头的行并保留上下各两行(用 awk 或 grep 更方便)
# sed 可用 range,但复杂时 prefer grep -n -C 或 awk

小结:

  • sed 是轻量级且高效的流式编辑工具,适合批量替换、删除、插入与简单的跨行处理;
  • 复杂任务可结合 awk / perl / python,或使用专门工具;在生产环境使用 -i 前请做好备份或在版本控制下操作。