sed 输出变了,文件就改了吗?18 项实测看清打印、替换与备份
练习文本处理时,最容易误判的现象是:终端已经显示替换后的内容,于是以为原文件也被修改。另一个常见困惑是:明明只让 sed 打印第一行,为什么整个文件都出现了,而且第一行还重复?
这次围绕华为云 KooLabs 的「Linux 文本“三剑客” — SED」实验目标,在实验操作桌面的 GNU sed 4.9 中,用自建文本样例做了 18 项断言。练习集中在 p、d、s、行地址和带备份的原地修改,文件写入只发生在临时目录。下面记录的是实际运行结果,不代表官方实验报告的评分,也不涉及修改系统配置。
先把输入、处理结果和磁盘文件分开看
准备五行样例,文件名使用新的练习文件:
printf '%s\n' alpha beta gamma delta epsilon > sample.txt
这份文件提供三个互相独立的检查对象:输入原文、sed 输出到终端的内容、命令运行后磁盘里保存的内容。测试时同时检查三者,比单看终端截图更容易发现误判。
例如运行:
sed '1,4d' sample.txt
终端只显示 epsilon。紧接着读取 sample.txt,仍然能看到完整五行。这里删除的是本次处理输出中的第 1 至 4 行;这条命令没有把修改写回原文件。实测脚本分别断言了输出等于一行、源文件仍等于原始五行,两项都通过。
第一行重复,来自两次输出
同样的五行输入,运行 sed '1p' sample.txt,结果是六行:alpha 出现两次,随后依次是 beta、gamma、delta、epsilon。
原因可以按执行过程理解:第一行命中 1p,显式打印一次;正常处理周期结束时还会自动打印一次。其余行没有命中 p,但仍有默认输出。
对照命令是:
sed -n '1p' sample.txt
这次只得到 alpha 一行。-n 控制默认打印,p 控制明确选中的打印操作。两者不是同一个开关。GNU 手册的 “Command-Line Options”章节 也说明了 -n 与自动打印的关系。
如果需求是“只要符合条件的行”,先写出筛选条件,再决定是否关闭默认打印,通常比看输出后反复加参数更清晰。
行范围、分离地址和正则,得到的是不同集合
本次样例中,以下结果都经过断言验证:
| 命令中的脚本 | 配合选项 | 输出 |
|---|---|---|
2,4p |
-n |
beta、gamma、delta |
1p;4p |
-n |
alpha、delta |
1~2p |
-n |
alpha、gamma、epsilon |
/^g/p |
-n |
gamma |
/beta/!d |
无 | beta |
$d |
无 | 前四行 |
逗号表达连续区间,分号连接独立指令。1~2 是本次 GNU sed 环境中的步进行地址,不能仅凭这次测试就断言其他 sed 实现行为相同;官方 GNU sed 手册“Numeric Addresses”章节 将这种写法列为 GNU 扩展。
实际维护脚本时,还应记录系统和 sed 实现。这里只验证了 GNU sed 4.9,没有做 macOS/BSD sed 的兼容性测试。
s 的默认范围是每行第一次匹配
把输入缩小成 2023 2023 2023 一行后,三种脚本的差异很直观:
s/2023/X/ -> X 2023 2023
s/2023/X/g -> X X X
s/2023/X/2 -> 2023 X 2023
三种结果分别对应每行首次匹配、每行所有匹配、每行第二次匹配。这些是本次相同输入的直接运行结果。要批量处理日志或配置,先用一行包含多个重复词的样例做对照,能迅速发现“只替换了一部分”的范围错误。
需要写回时,验证结果和备份
在临时目录里重新创建完整的五行 sample.txt 后,执行:
sed -i.bak '1,4d' sample.txt
这次验证了两件事:sample.txt 只剩 epsilon;sample.txt.bak 保留原始五行。两项断言都通过。测试脚本随后退出临时目录并自动清理自建样例,没有碰系统配置文件。
对于真实文件,建议先输出到另一个临时结果文件并查看差异,确认修改范围后再决定写回方式。备份后也应读取备份检查内容,不能只凭文件名存在就认为可以恢复。固定的 .bak 名称也不适合充当长期、多版本的备份策略。
尤其不要把“减少终端输出”与“保留文件内容”混为一谈。GNU 手册专门提醒:-n 与 -i 组合使用而缺少必要打印操作时,可能把原文件改为空文件。本次没有对真实文件尝试这种操作。
本次实测覆盖与边界
18 项断言覆盖了默认打印叠加 p、关闭默认打印、连续行与分离地址、GNU 步进地址、正则筛选、删除范围、取反条件、末行删除、三种替换范围、整行替换、追加模拟主机记录,以及普通输出和带备份写回后的文件内容。
断言脚本使用 Python 的 subprocess 调用实际 sed,用精确字符串比较验证结果,而不是自己重新实现 sed。最终终端输出为 SUMMARY: 18 assertions passed。这些小测试说明了本次环境和样例下的行为;它们没有覆盖链接文件、文件权限、并发写入、所有编码、所有平台或复杂多行脚本。
这次练习最有用的检查习惯是:每次都明确自己正在观察终端输出、内存中的处理结果,还是磁盘文件。确认这三个对象以后,再讨论“已经替换”“已经删除”或“可以恢复”,结论会准确得多。
实验入口:华为云 Linux SED 实验。本文由 AI 辅助整理,命令结果来自上述沙箱实测。
- 点赞
- 收藏
- 关注作者
评论(0)