sed 常用命令整理

sedStream Editor,流编辑器)是 Linux 中强大的非交互式文本处理工具

常见用途:

  • 文本替换、删除、插入
  • 按行/按模式筛选内容
  • 配合正则表达式进行批量处理
  • 与管道(|)配合处理命令输出

目录

  1. 命令格式
  2. 常用选项
  3. 地址(定位要处理的行)
  4. 核心命令
  5. 替换命令 s 的 flags
  6. 替换中的特殊字符
  7. 实际应用示例
  8. sed 与其他命令配合
  9. 文本去重技巧
  10. 注意事项与陷阱

命令格式

sed [选项] '地址命令' [输入文件]

# 常用写法
sed 's/old/new/' file            # 屏幕输出处理结果(原文件不变)
sed -i 's/old/new/g' file        # 直接修改文件(GNU 写法)
command | sed 's/old/new/g'      # 处理管道输入
# 注:macOS/BSD 上需写 `sed -i '' 's/old/new/g' file` 显式指定空备份后缀

常用选项

sed -n 'p' file                       # 静默模式(不自动打印),常配合 p 命令使用
sed -e 's/a/A/' -e 's/b/B/' file      # 多点编辑(执行多条命令)
sed -f script.sed file                # 从脚本文件读取 sed 命令
sed -i 's/old/new/g' file             # 直接修改文件内容(in-place)
sed -i.bak 's/old/new/g' file         # 先备份原文件为 .bak,再修改
sed -E 's/(abc)+/X/g' file            # 使用扩展正则表达式(ERE)
sed -r 's/(abc)+/X/g' file            # 同上(-E 的旧写法,GNU sed 兼容)

地址(定位要处理的行)

缺省地址表示处理所有行。可用多种方式组合定位。

# 按行号
sed '5p' file              # 打印第 5 行
sed '5,10p' file           # 打印 5~10 行
sed '5,$p' file            # 打印第 5 行到末尾
sed '5~2p' file            # 从第 5 行开始,每隔 2 行打印一次(GNU 扩展)
sed -n '1~2p' file         # 打印奇数行(-n 抑制默认输出)

# 按模式(用 /pattern/ 包裹)
sed '/error/p' file        # 打印包含 error 的行
sed '/error/d' file        # 删除包含 error 的行
sed '/^$/d' file           # 删除空行
sed '/^#/d' file           # 删除以 # 开头的注释行
sed '/start/,/end/p' file  # 打印从匹配 start 到匹配 end 之间的所有行

# 组合
sed '1,/error/d' file      # 删除从第 1 行到第一个匹配 error 的行
sed '/start/,+5d' file     # 从匹配 start 的行开始,删除其后再加 5 行(共 6 行)

核心命令

命令 说明 示例
s/regexp/replacement/[flags] 替换 's/foo/bar/g'
d 删除行 '/^$/d'
p 打印行 -n '/error/p'
i\text 在匹配行之前插入文本 '/pattern/i\新行'
a\text 在匹配行之后追加文本 '/pattern/a\新行'
c\text 用文本替换匹配行 '/pattern/c\新行'
y/source/dest/ 按字符逐个替换(类似 tr) 'y/abc/ABC/'
q 处理到此处即退出 '10q'
r file 读取 file 内容插入到匹配行后 '/pattern/r file'
w file 将匹配行写入 file '/error/w err.log'
n 读取下一行(覆盖模式空间) 'n; p'
N 追加下一行到模式空间(处理多行) 'N; s/\n/ /'
= 打印行号 '/error/='
l 打印行(显示不可见字符) 'l'

替换命令 s 的 flags

# g  全局替换(行内所有匹配,不加 g 只替换每行第一个)
sed 's/foo/bar/g' file

# n  只替换第 n 个匹配
sed 's/foo/bar/2' file     # 替换每行第 2 个 foo

# p  打印发生替换的行(常与 -n 配合看哪些行被改)
sed -n 's/foo/bar/p' file

# i  忽略大小写(GNU 扩展)
sed 's/FOO/bar/gi' file

# e  将替换结果作为 shell 命令执行(GNU 扩展,注意安全风险)
# 注意:e 必须作为唯一/最后的 flag,不能与 g、p、数字等其他 flag 组合使用
sed 's/^/echo /e' file

# 多重 flags 可组合(g 与 i 可以组合)
sed -i 's/old/new/gi' file

替换中的特殊字符(转义与引用)

# /  在替换内容中需要转义
sed 's/http:\/\///g' file
# 或使用 |、#、@ 等作为分隔符,更易读
sed 's|http://||g' file
sed 's#/usr/local##' file

# &  代表「匹配到的整个内容」
sed 's/[0-9]\+/[&]/g' file     # 把数字包到方括号里

# \1 ~ \9  代表正则中第 n 个捕获组
sed -E 's/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/\3\/\2\/\1/' file  # 2026-06-09 → 09/06/2026

# 大小写转换(GNU 扩展,替换内容里使用)
# \L  转为小写    \U  转为大写    \E  结束转换
sed 's/^[A-Z]\+/\L&/' file

实际应用示例

# 1. 替换文件内容(最常用)
sed -i 's/old/new/g' filename                # 直接修改文件
sed -i 's/old/new/g' *.txt                   # 批量替换多个文件
find . -name "*.conf" -exec sed -i 's/old/new/g' {} \;  # 递归替换

# 2. 删除操作
sed '/^$/d' file                 # 删除空行
sed '/^[[:space:]]*$/d' file     # 删除只包含空白字符的行
sed '/^#/d' file                 # 删除注释行
sed '/^$/d;/^#/d' file           # 一次删除空行和注释行
sed '5d' file                    # 删除第 5 行
sed '5,10d' file                 # 删除 5~10 行
sed '$d' file                    # 删除最后一行
sed -n '5!p' file                # 除第 5 行外都打印(注意 -n 抑制默认输出)
# 陷阱:去掉 -n 后 `sed '5!p' file` 会先自动打印一次,再用 p 多打一遍,结果是非第 5 行打 2 次、第 5 行 1 次

# 3. 插入与追加
sed '2i\这是插入的新行' file             # 在第 2 行前插入
sed '2a\这是追加的新行' file             # 在第 2 行后追加
sed '/pattern/i\在匹配行前插入' file
sed '/pattern/a\在匹配行后插入' file

# 4. 打印指定行
sed -n '1,5p' file              # 打印 1~5 行
sed -n '5p' file                # 打印第 5 行
sed -n '$p' file                # 打印最后一行
sed -n '/error/p' file          # 打印包含 error 的行(类似 grep)
sed -n '/start/,/end/p' file    # 打印两个模式之间的内容
sed -n '1~2p' file              # 打印奇数行
sed -n '2~2p' file              # 打印偶数行

# 5. 多行处理
sed 'N; s/\n/ /' file           # 将两行合并为一行(用空格连接)
sed 'N; s/\n//' file            # 合并为一行(直接拼接)

# 6. 配合管道
ps aux | sed -n '/apache/p'     # 等价于 ps aux | grep apache
cat file | sed 's/old/new/g' > newfile  # 处理后输出到新文件
# dmesg | grep -i error      # 忽略大小写匹配 error(grep 更直接)

# 7. 修改配置文件
sed -i 's/^#Port 22/Port 2222/' /etc/ssh/sshd_config  # 取消注释并改端口
sed -i 's/^Port.*/Port 2222/' /etc/ssh/sshd_config    # 直接改 Port 行
sed -i '/^SELINUX=/c\SELINUX=disabled' /etc/selinux/config  # 整行替换

# 8. 在每行首/行尾添加内容
sed 's/^/prefix: /' file        # 行首加前缀
sed 's/$/ suffix/' file         # 行尾加后缀
sed 's/.*/  &/' file            # 整行缩进 2 个空格

# 9. 提取特定列(简单场景)
# 提取 name= 后的值(BRE 写法;若同时使用 -E,要把 \( \) 改成 ( ),并把 * 转义或保留)
sed -n 's/.*name=\([^ ]*\).*/\1/p' file

# 10. 去除行首/行尾空白
sed 's/^[[:space:]]*//' file    # 去除行首空白
sed 's/[[:space:]]*$//' file    # 去除行尾空白

sed 与其他命令配合

# sed + grep:先过滤再处理
grep "error" log.txt | sed 's/error/ERROR/g'

# sed + awk:sed 做行级处理,awk 做字段级处理
cat file | sed '/^$/d' | awk '{print $1}'

# 多次 sed 管道(注意:-i 写在最后再处理文件更安全)
cat file | sed 's/a/A/' | sed 's/b/B/' | sed 's/c/C/'

# 用 sed 模拟 head / tail
sed '10q' file                  # 等价于 head -n 10 file
sed -n '6,$p' file              # 等价于 tail -n +6 file(跳过前 5 行,打印第 6 行起)
# 注意:tail -n +5 与 sed -n '5,$p' 不严格等价,前者跳过前 4 行、后者包含第 5 行

文本去重技巧

场景:把一份含有重复行的列表文件处理成每条只出现一次的结果。

示例输入

假设 fruits.txt 内容如下(从用户输入或日志里导出的,可能含重复项):

apple
banana
apple
cherry
banana
date
cherry

我们希望输出:

apple
banana
cherry
date

方法 1:用 sort -u(最简单,接受打乱顺序)

sort -u fruits.txt

输出:

apple
banana
cherry
date

⚠️ 副作用:原始顺序被打乱,会按字典序重排。


方法 2:用 awk保留原始顺序,推荐)

awk '!seen[$0]++' fruits.txt

原理

  • $0 代表当前整行内容
  • seen[$0] 是以行内容为 key 的关联数组
  • 第一次遇到某行时,seen[$0] 是空/0,取反为真 → 打印
  • 自增 ++ 把该 key 标记为 1
  • 之后再次遇到同一行时,seen[$0] 是 1,取反为假 → 跳过

方法 3:纯 sed不推荐,仅作了解)

网上流传的"纯 sed 去重"版本(如利用 hold space 做行级比对)在空行、超长行、含 / \ 这类特殊字符的行等场景下并不可靠。即使勉强能跑,写法也非常晦涩,调试和维护成本高。

这类写法可读性差、边界情况多。实际生产中请直接用方法 2(awk),可读性、稳定性和性能都更好。


方法 4:先排序去重,再恢复原顺序

awk '{print NR"\t"$0}' fruits.txt | sort -t$'\t' -k2,2 -u | sort -t$'\t' -k1,1n | cut -f2-

用行号做"暂存标签",先按内容去重,再按行号排序,最后去掉标签。


各方法对比

方法 是否保留原顺序 复杂度 适用场景
sort -u 不在意顺序的最简方案
awk !seen[]++ 推荐,通用、行序保持
sed ⭐⭐⭐⭐ 不推荐,仅了解思路
加行号两轮排序 ⭐⭐ 需要保留顺序又只用 sort 的场景

注意事项与陷阱

  1. -i 会直接修改原文件,建议先用不带 -i 的命令测试,确认无误再添加 -i
  2. 复杂替换务必加 -i.bak:原文件会备份为 file.bak,出错可回滚。
  3. 正则语法
    • 默认使用 BRE(基础正则),( ) | { } 等需要转义:\(abc\)\+
    • 使用 -E-r 切换为 ERE(扩展正则),更直观:sed -E 's/(abc)+/X/g'
  4. 特殊字符/&\ 在替换内容中有特殊含义,必要时用 \ 转义。
  5. macOS 与 Linux 的差异:macOS 的 BSD sed 要求 -i '' 显式指定备份后缀;GNU sed 可省略。跨平台脚本建议写 sed -i.bak 's/old/new/g' file
  6. 大文件处理:sed 是流式处理,内存占用低,适合处理 GB 级日志。

整理日期:2026 年 6 月 9 日 · 内容以 GNU sed 4.x 行为为准,macOS/BSD 上个别 flag 和 -i 用法有差异。

posted @ 2026-07-07 14:03  RK5123153  阅读(27)  评论(0)    收藏  举报