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 |
全局:该行所有匹配都替换,不只第一个 |
i 或 I |
忽略大小写(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'
十四、常见坑与建议
- 先不用 -i:先
sed '...' file看输出,确认无误再加-i。 - 元字符要转义:
.、*、[、]、/等按需用转义或换分隔符。 - 空格与换行:脚本里空格、换行要小心,
a后换行表示追加内容延续到下一行。 - macOS/BSD:-i 用法与 GNU 不同,要带备份后缀或
''。 - 大文件:-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、部分正则上略有差异。