shell的sed命令

Shell 的 sed 命令详解(新手详细版)

本文档面向零基础新手,从“sed 是干什么的”讲起,详细说明基本概念、寻址、替换、删除、插入、常用选项、正则与转义、实用示例等,并配有大量示例。


一、sed 是什么?

1.1 一句话理解

sed(Stream EDitor)是流式编辑器:对输入一行一行处理,按你给的“命令”做查找、替换、删除、插入等,再把结果输出。
默认不修改原文件,只把结果打印到标准输出;要改文件需用 -i 选项。

  • 流式:按行读入、按行处理、按行输出,适合管道和脚本。
  • 编辑器:能做替换、删行、插行等“编辑”操作。

1.2 典型用途

  • 批量替换文件里的字符串(如改配置、改路径);
  • 删除某些行(如空行、注释行);
  • 插入追加几行(如在某行前/后加内容);
  • 和管道配合,对命令输出做简单“清洗”。

二、基本语法

sed [选项] '脚本' [输入文件...]
  • 脚本:由一个或多个命令组成,告诉 sed 对“哪几行”做“什么操作”。
  • 输入:不写文件则从标准输入读(管道或键盘)。
  • 常见写法:sed 's/旧/新/' file.txt(把每行里第一次出现的“旧”换成“新”)。

示例:

# 把 file.txt 里每行第一个 hello 换成 hi,结果打印到屏幕
sed 's/hello/hi/' file.txt

# 从管道读
echo "hello world" | sed 's/hello/hi/'
# 输出:hi world

# 不写文件 = 从标准输入
sed 's/foo/bar/'
# 然后输入几行,每行回车后看到替换结果

三、核心概念:寻址 + 命令

3.1 寻址(对哪几行生效)

sed 的很多命令可以带寻址:只对满足条件的行执行命令。不写寻址就表示每一行

寻址写法 含义 示例
每一行 sed 's/a/b/'
n 第 n 行(n 为数字) sed '3s/a/b/' 只改第 3 行
$ 最后一行 sed '$s/a/b/'
n,m 第 n 到 m 行 sed '2,5s/a/b/'
n,+k 第 n 行及后面 k 行(部分 sed 支持) sed '2,+3s/a/b/'
/模式/ 包含该模式的行 sed '/error/s/old/new/'
n,m!! 对“不匹配”的行执行(取反) sed '3!s/a/b/' 除第 3 行外都替换

示例:

# 只替换第 2 行里的 first 为 second
sed '2s/first/second/' file.txt

# 只替换第 1 到 5 行
sed '1,5s/old/new/' file.txt

# 只替换包含 "apple" 的行
sed '/apple/s/red/green/' file.txt

# 只删除第 3 行
sed '3d' file.txt

# 删除最后一行
sed '$d' file.txt

3.2 常用命令(做什么)

命令 含义 示例
s/旧/新/ 替换:把“旧”换成“新”(每行默认只换第一次) sed 's/foo/bar/'
d 删除该行(不输出) sed '3d'sed '/^#/d'
p 打印该行(常与 -n 一起用,只打印匹配的) sed -n '3p'
a 文本 在该行后面追加一行 sed '2a hello'
i 文本 在该行前面插入一行 sed '2i hello'
c 文本 用“文本”整行替换该行 sed '2c new line'
y/源字符集/目标字符集/ 按字符一一替换(类似 tr) sed 'y/abc/ABC/'

下面按“替换、删除、打印、插入/追加、y”分开细讲。


四、替换命令 s(最常用)

4.1 基本形式

s/要替换的内容/替换成什么/[标志]
  • 默认只替换每行里第一次出现的那一处。
  • 分隔符不一定是 /,可以是别的(如 #|),只要三个一致即可,便于替换路径等含 / 的字符串。

示例:

# 每行第一个 hello 换成 hi
sed 's/hello/hi/' file.txt

# 分隔符用 #,适合内容里有很多 /
sed 's#/old/path#/new/path#' file.txt

# 替换 192.168.1.1 为 10.0.0.1(点要转义,见下节)
sed 's/192.168.1.1/10.0.0.1/' file.txt

4.2 替换标志(放在最后一格)

标志 含义
g 全局:该行所有匹配都替换,不只第一个
iI 忽略大小写(GNU sed)
p 若该行发生替换,则打印该行(常与 -n 一起用)
数字 只替换第 n 次出现,如 s/old/new/2
w 文件 把发生替换的行写入指定文件(GNU sed)

示例:

# 把所有 hello 都换成 hi
sed 's/hello/hi/g' file.txt

# 只替换每行第 2 个 old 为 new
sed 's/old/new/2' file.txt

# 忽略大小写
sed 's/hello/hi/gi' file.txt

4.3 正则、& 和反向引用 1 2

  • 要替换的内容里可以用正则替换成什么里可以用:
    • &:代表“本次匹配到的整段内容”;
    • 1、2、…:代表前面用 (...) 括起来的第 1、2、… 组。

示例:

# 给数字两边加括号:匹配到的数字用 & 表示
echo "price 100 yuan" | sed 's/[0-9]*/(&)/'
# 输出:price (100) yuan

# 调换顺序:把 "名 姓" 改成 "姓 名"
echo "zhang san" | sed 's/([^ ]*) ([^ ]*)/2 1/'
# 输出:san zhang

# 把 "year-month-day" 改成 "day/month/year"
echo "2025-02-25" | sed 's/([0-9]*)-([0-9]*)-([0-9]*)/3/2/1/'
# 输出:25/02/2025

注意:在基本正则里,括号要写成 ();在 GNU sed 的 -r 或 -E 下可用 (...) 不转义(见下节)。

4.4 扩展正则 -r / -E(少写反斜杠)

GNU sed 用 -r(或 -E)启用扩展正则,( )+?| 等不用再转义:

# 把 一个或多个数字 替换成 NUM
echo "abc123def456" | sed -r 's/[0-9]+/NUM/g'
# 输出:abcNUMdefNUM

# 调换顺序(不用 ( ))
echo "zhang san" | sed -r 's/([^ ]*) ([^ ]*)/2 1/'

五、删除行:d 命令

d 表示“删除这一行”(不输出到结果里)。

# 删除第 3 行
sed '3d' file.txt

# 删除最后一行
sed '$d' file.txt

# 删除第 2 到 5 行
sed '2,5d' file.txt

# 删除空行
sed '/^$/d' file.txt

# 删除以 # 开头的行(注释)
sed '/^#/d' file.txt

# 删除包含 "debug" 的行
sed '/debug/d' file.txt

# 删除从第一个含 "start" 的行到第一个含 "end" 的行(含首尾)
sed '/start/,/end/d' file.txt

六、打印行:p 命令 与 -n

  • p:把当前行再打印一遍。
  • 默认 sed 会自动打印“处理后的当前行”;所以不用 p 时也会看到结果。
  • -n:关闭“自动打印”,只输出你用 p 指定的那些行。
  • 组合 -n + p:只输出“被选中的行”,相当于“按条件取行”。

示例:

# 只打印第 3 行
sed -n '3p' file.txt

# 只打印第 2 到 5 行
sed -n '2,5p' file.txt

# 只打印包含 "error" 的行
sed -n '/error/p' file.txt

# 打印最后一行
sed -n '$p' file.txt

替换 + 只打印发生替换的行:

sed -n 's/old/new/p' file.txt
# 只输出“被替换过”的那几行

七、插入与追加:a、i、c

7.1 a:在该行后面追加一行(或几行)

# 在第 2 行后面追加 "new line"
sed '2a new line' file.txt

# 追加多行(用 n 换行,或 反斜杠续行)
sed '2a line1nline2' file.txt

7.2 i:在该行前面插入一行

# 在第 2 行前面插入 "inserted"
sed '2i inserted' file.txt

7.3 c:用新内容整行替换

# 把第 2 行整行换成 "replaced line"
sed '2c replaced line' file.txt

# 把含 "old" 的行都换成 "new line"
sed '/old/c new line' file.txt

示例:在“某模式行”后追加一行:

# 在包含 "server" 的行后面追加 "  listen 80;"
sed '/server/a   listen 80;' nginx.conf

八、按字符替换:y 命令

y/源字符集/目标字符集/:把源里的每个字符一一对应换成目标里的字符(长度要一样)。类似 tr

# 把 a→A, b→B, c→C
echo "abc" | sed 'y/abc/ABC/'
# 输出:ABC

# 小写转大写(26 个字母都要写全)
echo "hello" | sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'
# 实际更常用 tr:echo "hello" | tr 'a-z' 'A-Z'

九、多个命令:-e、分号、换行

要对同一输入执行多条 sed 命令,可以:

方式一:多个 -e

sed -e 's/foo/bar/' -e '3d' file.txt

方式二:用分号连在一起

sed 's/foo/bar/; 3d' file.txt

方式三:脚本里换行(单引号内)

sed '
s/old/new/
/^#/d
' file.txt

示例:先删空行,再删注释,再替换

sed -e '/^$/d' -e '/^#/d' -e 's/old/new/g' file.txt

十、修改原文件:-i(就地编辑)

默认 sed 不改文件,只把结果打到标准输出。要直接改文件,用 -i

注意:改错了难以恢复,建议先不用 -i 看效果,再加 -i。

# 直接改 file.txt(GNU sed)
sed -i 's/old/new/g' file.txt

# 先备份再改:生成 file.txt.bak,改的是 file.txt
sed -i.bak 's/old/new/g' file.txt

macOS/BSD sed:-i 后面必须跟备份后缀(可写空串表示不备份):

sed -i '' 's/old/new/g' file.txt
sed -i '.bak' 's/old/new/g' file.txt

十一、正则与转义(简要)

11.1 在“要替换的内容”里

  • . → 任意一个字符;要匹配字面点写 .
  • * → 前一个字符 0 次或多次。
  • ^ → 行首;$ → 行尾。
  • [ ] → 字符类;[^ ] → 取反。
  • (…) → 分组,替换里用 1、2 引用;用 -r 时可写 (...)

11.2 在“替换成什么”里

  • & → 本次匹配到的整段。
  • 1、2 → 第 1、2 个分组。
  • 要得到字面 :写 ;要字面 &:写 &

11.3 分隔符

当“要替换的内容”或“替换成什么”里有很多 / 时,可换分隔符:

sed 's#/usr/local#/opt#g' file.txt
sed 's|old|new|g' file.txt

十二、从文件读入与输出

12.1 输入:文件 vs 标准输入

sed 's/a/b/' file.txt
cat file.txt | sed 's/a/b/'

12.2 输出:默认标准输出;-i 才写回文件

sed 's/a/b/' file.txt > new.txt   # 结果重定向到新文件,原文件不变
sed -i 's/a/b/' file.txt          # 直接改 file.txt

十三、实用示例汇总

13.1 替换

# 全文把 old 换成 new(每行所有出现)
sed 's/old/new/g' file.txt

# 只替换每行第 2 个
sed 's/old/new/2' file.txt

# 替换路径
sed 's#/home/old#/home/new#g' file.txt

# 删除行首空白
sed 's/^[[:space:]]*//' file.txt

# 删除行尾空白
sed 's/[[:space:]]*$//' file.txt

13.2 删除行

# 删空行
sed '/^$/d' file.txt

# 删注释(# 开头)
sed '/^#/d' file.txt

# 删空行和只含空白行
sed '/^[[:space:]]*$/d' file.txt

# 删第 1 行
sed '1d' file.txt

# 删最后一行
sed '$d' file.txt

13.3 提取行(-n + p)

# 取第 10 行
sed -n '10p' file.txt

# 取 20~30 行
sed -n '20,30p' file.txt

# 取含 "error" 的行
sed -n '/error/p' file.txt

13.4 插入/追加

# 第 1 行前插入标题
sed '1i === HEADER ===' file.txt

# 最后一行后追加
sed '$a --- END ---' file.txt

# 在含 "server {" 的行后追加 "  listen 80;"
sed '/server {/a   listen 80;' file.txt

13.5 与管道配合

# 把 ls 输出里的 .txt 替换成 .bak
ls | sed 's/.txt$/.bak/'

# 取某命令输出的第 2 行
some_command | sed -n '2p'

十四、常见坑与建议

  1. 先不用 -i:先 sed '...' file 看输出,确认无误再加 -i
  2. 元字符要转义.*[]/ 等按需用 转义或换分隔符。
  3. 空格与换行:脚本里空格、换行要小心,a 后换行表示追加内容延续到下一行。
  4. macOS/BSD:-i 用法与 GNU 不同,要带备份后缀或 ''
  5. 大文件:-i 会写临时文件再覆盖,注意磁盘空间。

十五、选项与命令速查

选项 含义
-n 不自动打印,只输出用 p 等指定的行
-i 就地编辑(GNU:-i 或 -i.bak)
-e '脚本' 指定一段脚本,可多个 -e
-r / -E 扩展正则(少写 )
-f 文件 从文件读脚本(多行命令可写进文件)
命令 含义
s/旧/新/g 替换,g=全局
d 删除行
p 打印行(常配 -n)
a 文本 行后追加
i 文本 行前插入
c 文本 整行替换
y/源/目标/ 按字符一一替换

十六、小结

  • sed 是流式编辑器:按行读、按行处理、按行输出;默认不改原文件。
  • 寻址:行号(n、$、n,m)、模式(/pattern/),决定命令对哪几行生效。
  • 最常用s/// 替换(含 g、i、&、1);d 删行;-n + p 取行;a/i/c 追加/插入/整行替换;y/// 按字符替换。
  • 多命令:-e、分号、换行;改文件用 -i,并先不用 -i 验证。

建议在测试文件上多练:替换、删空行、删注释、取某几行、在某行前后加内容,再结合 shell的grep命令.md 理解“查找”和“替换”的配合使用。


文档以 GNU sed 为主;BSD/macOS sed 在 -i、部分正则上略有差异。

发表评论