Linux基础及应用教程:文本三剑客之sed
一、实验目标
- 理解
sed的工作原理(流编辑器,逐行处理) - 掌握
sed的基本使用方式:打印、删除、替换、插入/追加等 - 学会使用地址(行号、模式匹配)精确选择要处理的行
- 掌握常见选项(如
-n、-e、-i等)的用法 - 能够结合正则表达式使用
sed对文本内容进行批量替换和格式处理 - 学会在管道中配合其他命令、系统自带配置文件进行实战操作
二、实验环境
- 实验平台:VMware 虚拟机
- 操作系统:CentOS 7
- 登录用户:
njucm - 普通用户密码:
123456 - root 密码:
123456
三、实验内容与步骤
文件准备(创建实验环境)
本实验将同时使用自建测试文本和系统自带配置文件的副本进行练习,避免误改系统关键文件。
# 1. 创建实验目录
mkdir -p ~/sed_lab
cd ~/sed_lab
# 2. 准备一个多行测试文本文件
cat > poem.txt << 'EOF'
The quick brown fox jumps over the lazy dog.
The quick brown fox likes Linux.
linux is powerful and flexible.
SED is a stream editor.
Sed can replace, delete, insert and transform text.
EOF
# 3. 准备一个带有简单配置格式的文件
cat > config.txt << 'EOF'
# Sample configuration file
HOST=localhost
PORT=8080
USER=admin
PASS=123456
LOG_LEVEL=info
EOF
# 4. 复制系统自带文本文件作为练习(只在自己的家目录操作)
# /etc/passwd 是很典型的系统用户信息文件,这里只拷贝一份出来练习
cp /etc/passwd passwd.sample
# 再准备一个日志模拟文件
cat > app.log << 'EOF'
[2025-01-01 10:00:00] INFO Service started on port 8080
[2025-01-01 10:05:00] WARN High memory usage detected
[2025-01-01 10:10:00] ERROR Failed to connect to database
[2025-01-01 10:15:00] INFO Service is running
EOF
之后的所有 sed 练习命令均在 ~/sed_lab 目录中完成。
任务1:sed命令基础使用
-
查看文件内容:默认行为(逐行读取并输出)
# 使用 sed 直接查看文件(等价于 cat + 过滤) sed '' poem.txt # 传统写法:sed -e '命令' sed -e '' poem.txt说明:空命令
''表示不对文本进行修改,只是原样输出。 -
打印指定行:
p命令与-n选项# 打印第 2 行 sed -n '2p' poem.txt # 打印第 1 到 3 行 sed -n '1,3p' poem.txt # 打印最后 1 行($ 表示最后一行) sed -n '$p' poem.txt-n:关闭默认输出,只输出被p命令选中的行。 -
多条命令执行:使用
-e或{}分组# 用 -e 指定多条命令 sed -n -e '1p' -e '$p' poem.txt # 打印首行和末行 # 使用 {} 在地址范围内执行多条命令 sed -n '2,4{=;p}' poem.txt # 打印 2-4 行以及行号(=) -
显示行号:
=命令# 打印所有行的行号和内容 sed -n '=;p' poem.txt
任务2:文本替换与正则
在 sed 中,最常用的命令之一就是替换命令 s/模式/替换/标志。
# 1. 最基本的替换:只替换每行的第一个匹配
sed 's/Linux/Unix/' poem.txt
# 2. 全局替换:行内所有匹配都替换(加 g 标志)
sed 's/linux/Linux/g' poem.txt
# 注意:sed 默认区分大小写,Linux 与 linux 不一样
# 可以先统一大小写再替换,或用正则匹配多种写法
使用正则表达式进行模式匹配:
# 3. 使用正则匹配单词边界:只替换单词 'Sed'(不误伤单词内部)
sed 's/\<Sed\>/sed/g' poem.txt
# 4. 替换包含特殊字符的内容:使用其他分隔符,如 #
sed 's#8080#9090#g' app.log
# 5. 使用 & 引用匹配到的内容
# 把所有包含 Linux 的行中 'Linux' 替换为 '[Linux系统]'
sed 's/Linux/[&系统]/g' poem.txt
# 6. 使用括号分组和 \1、\2 反向引用(GNU sed 要用 -r 或 -E)
sed -r 's/(HOST)=(.+)/\1=192.168.0.1/' config.txt
# 7. 忽略大小写匹配(GNU sed 支持 I 标志)
sed 's/linux/Linux/Ig' poem.txt
只在匹配某种模式的行中进行替换:
# 只在包含 'INFO' 的日志行中把 'Service' 改成 'Server'
sed '/INFO/s/Service/Server/' app.log
# 只在行号 2-4 中替换 'quick' 为 'slow'
sed '2,4s/quick/slow/' poem.txt
任务3:行选取、删除与插入
删除行:d 命令
# 1. 删除第 1 行
sed '1d' poem.txt
# 2. 删除第 2-3 行
sed '2,3d' poem.txt
# 3. 删除所有包含 ERROR 的日志行
sed '/ERROR/d' app.log
# 4. 删除空行
sed '/^$/d' poem.txt
插入与追加:i(在前插入)、a(在后追加)
# 1. 在第 1 行前插入一行标题(注意末尾不用写 \)
sed '1i This is a poem about Linux.' poem.txt
# 2. 在文件末尾追加一行($ 表示最后一行)
sed '$a This is the end of the poem.' poem.txt
# 3. 在包含 'SED' 的行前插入注释
sed '/SED/i # SED related line below' poem.txt
替换整行内容:c 命令
# 将第 2 行整行替换为固定文本
sed '2c <This line has been replaced by sed>' poem.txt
# 将包含 'WARN' 的日志行全部替换为统一提示
sed '/WARN/c [WARN] please pay attention to system performance.' app.log
多行范围操作:地址范围 + 命令
# 对从 'HOST' 开始到 'USER' 所在行的范围内,添加注释前缀 #
sed '/HOST/,/USER/s/^/# /' config.txt
# 删除从 'WARN' 到 'ERROR' 之间(含)所有日志行
sed '/WARN/,/ERROR/d' app.log
任务4:结合管道与系统文本
本任务通过 passwd.sample 等系统文本的副本,模拟运维场景。
# 1. 使用管道只提取系统用户名前两列
# /etc/passwd 每行格式一般为:用户名:密码占位:UID:GID:注释:家目录:Shell
cat passwd.sample | sed 's/:.*//'
# 2. 显示 UID >= 1000 的普通用户(结合 awk 或 grep)
# 简单示例:先用 grep,再用 sed 清理字段
grep ':/home/' passwd.sample | sed 's/:.*//'
# 3. 配合行号查看特定配置行
nl -ba config.txt | sed -n '1,5p'
# 4. 在管道中对日志进行快速过滤与替换
cat app.log | sed '/INFO/d' | sed 's/ERROR/FATAL/g'
将 sed 与其他命令组合:
# 5. 实时查看某个日志并用 sed 高亮(简单方法:添加标签)
tail -f app.log | sed 's/ERROR/[ERROR]/'
# 6. 从 ps 输出中用 sed 提取特定字段(示例)
ps aux | sed -n '1p; /sshd/p'
任务5:配置文件批量修改实战
本任务模拟实际运维场景,对配置文件进行批量修改,并学习 -i 选项(原地修改)和备份。
一、在不修改原文件的前提下,预览修改效果
cd ~/sed_lab
# 1. 将 config.txt 中的 PORT 改为 9090(仅预览)
sed 's/^PORT=8080/PORT=9090/' config.txt
# 2. 将 LOG_LEVEL 从 info 改为 debug(仅预览)
sed 's/^LOG_LEVEL=info/LOG_LEVEL=debug/' config.txt
二、使用 -i 选项直接修改文件(务必注意备份)
# 1. 先查看原文件内容
cat config.txt
# 2. 修改前做好备份(推荐)
cp config.txt config.txt.bak
# 3. 使用 sed -i 原地修改(部分系统要求 -i 后必须直接跟备份后缀)
# 方式一:手动备份 + 简单 -i
sed -i 's/^PORT=8080/PORT=9090/' config.txt
# 方式二:让 sed 自动生成备份文件
sed -i.bak 's/^LOG_LEVEL=info/LOG_LEVEL=debug/' config.txt
# 4. 查看修改结果
cat config.txt
ls config.txt*
三、综合实战:统一修改密码策略、注释无用配置
# 假设我们决定不再在配置文件中存储明文密码,
# 用 sed 将 PASS 字段整行注释掉,并添加说明
cp config.txt config.txt.secure.bak
# 1. 注释掉 PASS 行
sed -i 's/^PASS/#PASS/' config.txt
# 2. 在 PASS 行后追加一行说明
sed -i '/^#PASS/a # NOTE: password is now managed by an external secret manager.' config.txt
# 3. 检查最终结果
cat config.txt
四、实验报告要求
- 逐条记录任务中关键
sed命令的使用方法与执行结果(可包含命令、输入文件片段、输出截图)。 - 总结
sed中地址选择(行号、正则模式、范围)与命令(p、d、s、i、a、c等)的组合用法。 - 解释
s/模式/替换/标志中各部分含义,并列举至少 3 个具体例子(含g、I、分组与反向引用等)。 - 以
config.txt或passwd.sample为例,设计一个你自己的“批量修改”需求,并通过sed给出实现方案和步骤说明。 - 对比
sed与grep、awk的侧重点,思考在实际运维/数据处理场景中各自适用的场景。
五、常见问题解答
-
Q:为什么我用
sed 's/a/b/' file后文件内容没有改变?
A:不加-i时,sed默认只是将修改后的结果输出到标准输出(终端),并不会修改原文件本身。如果你希望真正修改文件,请使用sed -i(建议搭配备份)或重定向输出到新文件。 -
Q:
sed -i在不同系统上的用法一样吗?
A:在 GNU sed(如 CentOS)中,sed -i 'script' file和sed -i.bak 'script' file都可以;在某些 BSD/ macOS 上,-i后面必须紧跟备份后缀(可以是空字符串)。在 VMware 的 CentOS 环境下,一般使用 GNU sed,示例命令可以直接使用。 -
Q:如何避免错误的替换操作“毁掉”配置文件?
A:建议遵循以下原则:- 先不加
-i,在终端中预览输出效果。 - 对重要文件操作前,先
cp file file.bak做好备份。 - 对系统关键文件(如
/etc/passwd)只操作副本,正如本实验使用的passwd.sample。
- 先不加
-
Q:正则中的
.、*等字符在 sed 里怎么用?
A:sed内部使用的是基本正则(BRE),多数情况下和你在grep中的写法类似:.:匹配任意单个字符*:匹配前一个字符 0 次或多次^和$:分别表示行首和行尾
+、?、|等)需要在 GNU sed 中使用-r或-E开启扩展正则。 -
Q:如何只对包含某个关键字的行做替换?
A:可以采用“地址/命令”的组合写法,例如:
这表示:在匹配到sed '/INFO/s/Service/Server/' app.logINFO的行中,执行后面的替换命令;不匹配的行不受影响。