sed应用笔记
Sed 学习笔记
这是一份稍微整理了一下的 sed 学习笔记。
我是把它当作“流式编辑器”来理解的,核心在于它不打开文件,而是把数据流读进来,处理完,扔出去。刚开始学的时候觉得语法反人类,后来发现这东西处理配置文件、批量改代码、分析日志简直是神器。
0. 核心心法
sed 的工作流程其实就三步:
- 读入一行到模式空间(Pattern Space)。
- 执行你给它的命令。
- 打印结果(除非你让它别打),然后清空空间,读下一行。
通用公式:
sed [选项] '地址+命令' 文件名
1. 基础:替换 (s)
这是最常用的功能,没有之一。
基本语法: s/旧的/新的/标记
# 最简单的替换,只替每行第一个
echo "hello world, hello sed" | sed 's/hello/hi/'
# 输出: hi world, hello sed
# 全局替换 (加个 g) -> Global
echo "hello world, hello sed" | sed 's/hello/hi/g'
# 输出: hi world, hi sed
很多人不知道如果不加
g,它只动第一处。另外,那个分隔符/其实是可以换的!当你在处理 URL 或者文件路径时,满屏的转义符
\/usr\/local\/bin看着眼晕。换成
#或者@瞬间清爽:
# 难看版
sed 's/\/usr\/local\/bin/\/usr\/bin/g' path.txt
# 优雅版 (推荐)
sed 's#^/usr/local/bin#/usr/bin#g' path.txt
2. 定位
如果不指定地址,sed 会处理每一行。但通常我们只想处理特定部分。
按行号
# 只删除第 2 行
sed '2d' file.txt
# 删除第 2 到第 5 行
sed '2,5d' file.txt
# 删除从第 3 行到最后一行 ($ 代表末尾)
sed '3,$d' file.txt
按正则匹配 (Regex)
这才是 sed 的灵魂。
# 只有包含 "error" 的行,才把 "warn" 替换成 "critical"
sed '/error/s/warn/critical/g' log.txt
# 删除所有空行 (匹配开头即结尾)
sed '/^$/d' file.txt
# 删除所有注释行 (以 # 开头的)
sed '/^#/d' config.ini
3. 那些常用但容易忘的命令
除了 s (替换),这几个必须背下来:
-n 和 p (打印)
默认情况下 sed 会把所有行都打印出来。
如果只想看处理过的行,或者匹配到的行,必须配合 -n (silent) 和 p (print)。
# 只打印第 5 行 (没 -n 会打印全部,且第 5 行打两次,巨坑)
sed -n '5p' file.txt
# 像 grep 一样用:只打印包含 "failed" 的行
sed -n '/failed/p' access.log
d (删除)
上面用过很多次了,不再赘述。
场景:把配置文件里带 # 的注释全删了,生成一个纯净版配置。
sed '/^#/d' nginx.conf
i (插入) 和 a (追加)
i(insert): 在当前行之前插。a(append): 在当前行之后插。
# 在含有 "Listen" 的行后面,加一行 "server_name localhost;"
sed '/Listen/a server_name localhost;' nginx.conf
4. 高级操作:分组与反向引用
这个学会了才算真正入门 sed。当你需要保留一部分内容,修改另一部分内容时使用。
核心是 () 和 \1, \2。
场景:把 name: value 格式改成 value = name。
echo "lang: python" | sed -E 's/(.*): (.*)/\2 = \1/'
# 输出: python = lang
()把内容包起来。\1代表第一个括号匹配到的内容,\2代表第二个。- 注意:加
-E是为了支持扩展正则,不然括号得写成\(\),太丑了。
**还有一个神器 &**:
它代表“刚才匹配到的所有内容”。
# 给所有的数字加上方括号
echo "ID 12345" | sed 's/[0-9]\+/[&]/g'
# 输出: ID [12345]
5. 范围匹配 (Range)
这个功能用来截取日志非常棒。语法是 '/开始标记/,/结束标记/ 命令'。
场景:提取日志中从 “Start” 到 “End” 之间的所有行。
sed -n '/Start/,/End/p' app.log
6. 关于 -i (直接修改文件)
最容易翻车的地方。
sed 默认只输出到屏幕,不改文件。想改文件要加 -i。
但是macOS 和 Linux 的 sed 在这里不一样!
- Linux (GNU sed):
sed -i 's/a/b/' file.txt(直接改,不备份) - macOS (BSD sed): 强制要求跟一个备份后缀。如果你不想要备份,必须给一个空字符串。
跨平台兼容写法(或者为了安全起见):
# 修改 file.txt,同时生成一个 file.txt.bak 备份
sed -i.bak 's/foo/bar/' file.txt
在写 CI/CD 脚本或者 Dockerfile 时,最好先确认环境是 Linux 还是 Mac,或者干脆用临时文件
sed ... > temp && mv temp file,虽然土,但是稳。
7. 什么时候不要用 Sed?
虽然 sed 很强,但下面情况需要切换到 awk 或者 Python:
- 涉及到多行逻辑时:虽然
sed有N,H,G(Hold Space) 这些命令可以处理多行,但写法非常像汇编语言,极难维护。几个月后你自己都看不懂。 - 需要进行数学运算时:
sed算数很痛苦。 - CSV/JSON 处理:用
sed处理 CSV 碰到带逗号的字段会死人;处理 JSON 请直接用jq。
8. 速查 Cheat Sheet
最后整理几个我平时 alias 或者写在脚本里的常用的:
# 1. 批量删除行尾空格 (强迫症福音)
sed -i 's/[ \t]*$//' file.txt
# 2. 给文件每一行加双引号 (处理 SQL 列表时很有用)
sed 's/^/"/; s/$/"/' list.txt
# 3. 打印文件的第 10 到 20 行
sed -n '10,20p' file.txt
# 4. 获取本机 IP (配合 ifconfig/ip addr,只取数字部分)
# 这是一个典型的链式处理
ifconfig eth0 | grep 'inet ' | sed 's/^.*inet //g' | sed 's/ *netmask.*$//g'
如果觉得 sed 的列处理能力(比如“修改每行的第3个单词”)有点弱,那下一站应该是 Awk。
