章节大纲

  • sed(流编辑器)简介

    sed(stream editor,流编辑器)是 Unix 系统中的一个文本处理工具,可用于解析和转换文本文件,且支持多个操作系统。尽管在许多用途上已经被 perl(或更早的 AWK)取代,但 sed 在 Shell 脚本中的简单文本转换仍然有一定的应用价值。

    sed面向行(line-oriented)的,它逐行处理输入,支持正则表达式匹配和替换


    1. sed 的基本使用

    1.1 s(substitution,替换)命令

    sed 最常用的功能是 s 命令(替换),用于将一种模式替换为另一种模式,例如:

    sed 's/cat/dog/g' input.txt > output.txt
    

    以上命令会将 input.txt 中的 "cat" 替换为 "dog",并输出到 output.txt。其中:

    • s/cat/dog/:将 cat 替换为 dog
    • g(global):表示替换行内所有匹配项,而不仅仅是第一个

    建议:使用单引号 '' 避免 Shell 误解析特殊字符:

    sed 's/cat/dog/g' input.txt > output.txt
    

    1.2 多个替换

    可以使用 -e 选项进行多个模式替换:

    sed -e 's/cat/dog/g' -e 's/meow/woof/g' input.txt > output.txt
    

    1.3 sed 作为管道处理

    sed 也可用于管道操作:

    echo "Hello cat" | sed 's/cat/dog/g'
    

    输出:

    Hello dog
    

    2. 复杂模式匹配

    2.1 扩展正则表达式

    默认情况下,sed 仅支持基本正则表达式(BRE),如需使用扩展正则表达式(ERE),需要:

    • GNU sed 使用 -r
    • BSD sed(macOS 默认安装) 使用 -E

    示例:

    sed -r 's/<(.*)>/<\1><\/\1>/g' input.txt
    

    以上命令会将 <a> 替换为 <a></a>


    2.2 组匹配与替换

    使用 () 进行分组匹配,并在替换中使用 \1, \2, ... 引用:

    echo "abc" | sed -r 's/(a)(b)(c)/\3\2\1/'
    

    输出:

    cba
    

    3. 编程与高级用法

    3.1 逐行操作

    sed 逐行处理数据,每次仅处理一行。如需跨行操作,可使用:

    • N(读取下一行到缓冲区)
    • Hg(存入/获取缓冲区)

    3.2 合并多行

    tr 命令比 sed 更适合合并所有行:

    tr '\n' ' ' < input.txt > output.txt
    

    tr 逐字符处理,不会占用大量内存,而 sed 会加载整个文件到内存。


    4. 相关命令

    • grep:选择符合条件的行
    • tr:进行单字符转换
    • awkperl:处理复杂文本任务

    5. sed 选项

    5.1 POSIX sed 选项

    -n      # 仅通过 `p` 命令输出匹配内容
    -e      # 指定多个 `sed` 命令
    -f      # 从文件读取 `sed` 命令
    

    5.2 GNU sed 额外选项

    --version       # 显示版本
    --help          # 显示帮助
    --quiet, --silent  # 与 `-n` 类似
    --in-place[=SUFFIX]  # 直接修改文件内容(可选备份)
    --regexp-extended, -r  # 启用扩展正则
    

    5.3 BSD sed 额外选项(macOS 默认)

    -E    # 启用扩展正则
    -i    # 直接修改文件内容(不支持 `--in-place`)
    

    6. 正则表达式支持

    sed 使用 POSIX 基本正则表达式(BRE),GNU sed 支持 扩展正则表达式(ERE)

    表达式 描述
    * 匹配前面字符 0 次或多次
    . 匹配任意单个字符
    ^ 匹配行首
    $ 匹配行尾
    [abc] 匹配 abc
    [^abc] 匹配非 abc 的字符
    \( \) 进行分组(适用于 \1, \2
    {i,j} 匹配 i 到 j 次
    \b 单词边界(GNU sed 扩展)

    7. sed 一行命令(Oneliners)

    7.1 简单替换

    sed "s/concieve/conceive/" file.txt   # 仅替换每行的第一个匹配项
    sed "s/concieve/conceive/g" file.txt  # 替换所有匹配项
    

    7.2 多次替换

    sed "s/concieve/conceive/g; s/recieve/receive/g" file.txt
    

    7.3 使用组匹配

    echo "abccbd" | sed -r "s/a([bc]*)d/\1/g"
    # 结果:bccb
    

    7.4 处理日期格式

    echo "03/11/2015 23:54:03" | sed -r "s/([0-9]+)\/([0-9]+)\/([0-9]+)/\3-\2-\1/g"
    # 结果:2015-11-03 23:54:03
    

    7.5 处理引号

    sed "s/\x22/'/g" file.txt  # 将双引号 `"` 替换为单引号 `'`
    

    7.6 忽略大小写

    echo "Hallo" | sed "s/hallo/hello/gi"
    # 结果:hello
    

    7.7 替换字母

    echo "a2" | sed "s/[[:alpha:]]/z/g"
    # 结果:z2
    

    8. sed 的局限性

    • 不支持非贪婪匹配.*?
      echo "abcbbc" | perl -pe "s/a.*?c/ac/"
      # 结果:acbbc
      
    • 不支持 Perl 风格的 \d, \D, \A, \Z
    • GNU sed 扩展特性不适用于所有 sed 版本

    🎯 总结sed 适用于行级别的文本转换,但复杂任务建议使用 awkperl