sed 核心知识点
第一步:准备示例文本文件
请将以下内容保存为一个名为 data.txt
的文本文件。这个文件模拟了一些常见的日志或配置文件片段,包含了我们需要练习的各种元素。
# /etc/config/app_settings.conf
# Application Configuration File
[General]
AppName=MyApp
Version=1.0.3
LogLevel=INFO
DebugMode=false
[Database]
DB_Host=db.example.com
DB_Port=3306
DB_User=app_user
DB_Pass=S3cr3tP@ssw0rd! # Default password, please change!
DB_Name=production_db
[Server]
ListenAddress=0.0.0.0
ListenPort=8080
MaxConnections=1000
UseSSL=true
# User List Section - TODO: Move to database
User1=alice ; admin
User2=bob ; user
User3=charlie ; user # Temporary account
# Log entries simulation
[2023-10-27 10:00:01] INFO: Application MyApp version 1.0.3 started.
[2023-10-27 10:00:05] DEBUG: Connection pool initialized. (DebugMode is off)
[2023-10-27 10:01:15] WARN: MaxConnections nearing limit (950/1000).
[2023-10-27 10:02:00] ERROR: Failed to connect to secondary service on 192.168.1.254:9999
[2023-10-27 10:02:10] INFO: User 'alice' logged in.
[2023-10-27 10:05:30] INFO: Configuration file reloaded.
[2023-10-27 10:10:00] ERROR: Database query failed for user 'bob'. SQLState: HY000
第二步:学习 sed
核心功能及典型任务
现在,我们来逐一学习 sed
的核心功能。sed
(Stream EDitor) 是一个极其强大的文本处理工具,尤其擅长基于行进行编辑。掌握它的核心功能对于运维工作非常有帮助。
基础语法: sed [选项] '命令' [输入文件...]
重要提示:
- 默认情况下,
sed
不会修改原始文件,而是将处理结果输出到标准输出 (stdout)。 - 使用
-i
选项可以直接修改文件(请极其小心使用,建议先不带-i
测试,或者使用-i.bak
创建备份)。 - 单引号
' '
用于包围sed
命令,防止 Shell 解释其中的特殊字符。
场景 1: 打印特定行 (行寻址与打印 p
)
sed
默认会打印处理后的每一行。-n
选项可以禁止默认打印,常与 p
(print) 命令结合使用,只打印我们明确指定的行。
-
任务: 打印文件的第 3 行。
- 命令:
sed -n '3p' data.txt
- 解释:
-n
禁止默认输出,3
是行地址,p
是打印命令。只打印第 3 行。
- 命令:
-
任务: 打印文件的第 5 行到第 8 行。
- 命令:
sed -n '5,8p' data.txt
- 解释:
5,8
是行地址范围,打印这个范围内的行。
- 命令:
-
任务: 打印所有包含 "ERROR" 的行。
- 命令:
sed -n '/ERROR/p' data.txt
- 解释:
/ERROR/
是一个正则表达式地址,匹配包含 "ERROR" 的行,p
打印匹配行。
- 命令:
-
任务: 打印所有以 "#" 开头的行(注释行)。
- 命令:
sed -n '/^#/p' data.txt
- 解释:
/^#/
正则表达式地址,^
表示行首,#
是要匹配的字符。
- 命令:
-
任务: 打印从包含 "[Database]" 的行开始,到第一个空行之间的所有行。
- 命令:
sed -n '/\[Database]/,/^$/p' data.txt
- 解释:
/\[Database]/,/^$/
是一个由两个正则表达式定义的地址范围。[
需要转义\[
。/^$/
匹配空行。
- 命令:
场景 2: 删除特定行 (行寻址与删除 d
)
d
(delete) 命令用于删除匹配的行。注意,默认情况下 sed
只是不打印这些行到标准输出,原始文件不变。
-
任务: 删除所有空行。
- 命令:
sed '/^$/d' data.txt
- 解释:
/^$/
匹配空行,d
删除匹配的行。
- 命令:
-
任务: 删除所有注释行(以 "#" 开头)。
- 命令:
sed '/^#/d' data.txt
- 解释:
/^#/
匹配注释行,d
删除。
- 命令:
-
任务: 删除第 10 行。
- 命令:
sed '10d' data.txt
- 解释:
10
是行地址,d
删除第 10 行。
- 命令:
-
任务: 删除从第 1 行到第 3 行。
- 命令:
sed '1,3d' data.txt
- 解释:
1,3
是行地址范围,d
删除这个范围内的行。
- 命令:
-
任务: 删除所有包含 "DEBUG" 的行。
- 命令:
sed '/DEBUG/d' data.txt
- 解释:
/DEBUG/
匹配包含 "DEBUG" 的行,d
删除。
- 命令:
场景 3: 替换文本 (替换 s
)
这是 sed
最常用、最强大的功能。s
(substitute) 命令用于查找和替换。
基本语法: s/查找模式/替换字符串/[标志]
常用标志:
g
: 全局替换 (Global),替换行内所有匹配项,而不仅仅是第一个。i
: 忽略大小写 (Ignore case),(GNU sed 特有)。
-
任务: 将每行中第一次出现的 "INFO" 替换为 "Information"。
- 命令:
sed 's/INFO/Information/' data.txt
- 解释:
s
表示替换。/INFO/
是查找模式。/Information/
是替换字符串。默认只替换每行第一个匹配项。
- 命令:
-
任务: 将文件中所有的 "user" (小写) 替换为 "account"。
- 命令:
sed 's/user/account/g' data.txt
- 解释:
g
标志表示全局替换,替换行内所有出现的 "user"。
- 命令:
-
任务: 将数据库密码那一行 (
DB_Pass=...
) 中的密码替换为 "[REDACTED]"。- 命令:
sed '/^DB_Pass=/ s/=.*/=[REDACTED]/' data.txt
- 解释:
/^DB_Pass=/
是地址,只在匹配此模式的行上执行后面的s
命令。s/=.*/=[REDACTED]/
查找第一个=
及其之后的所有内容 (.*
),并替换为=[REDACTED]
。
- 命令:
-
任务: 更改数据库主机名
db.example.com
为prod-db-replica.internal
。- 命令:
sed 's/db\.example\.com/prod-db-replica.internal/' data.txt
- 解释: 在查找模式中,
.
是正则表达式元字符(匹配任意单个字符),需要用\
转义 (\.
) 来匹配字面上的点。
- 命令:
-
任务: 使用不同的分隔符(例如
#
或|
)进行替换,当查找或替换内容包含/
时特别有用。例如,更改日志中的 IP 地址192.168.1.254
为10.10.0.10
。- 命令:
sed 's|192\.168\.1\.254|10.10.0.10|' data.txt
- 解释: 使用
|
作为s
命令的分隔符,避免了转义/
。仍然需要转义.
。
- 命令:
-
任务: 只在包含 "ERROR" 的行中,将 "Failed" 替换为 "Attempted"。
- 命令:
sed '/ERROR/ s/Failed/Attempted/' data.txt
- 解释:
/ERROR/
是地址,s
命令只应用于匹配该地址的行。
- 命令:
场景 4: 同时执行多个命令
可以用分号 ;
或 -e
选项来执行多个 sed
命令。
- 任务: 删除所有空行,并将 "WARN" 替换为 "Warning"。
- 命令 (使用分号):
sed '/^$/d ; s/WARN/Warning/g' data.txt
- 命令 (使用 -e):
sed -e '/^$/d' -e 's/WARN/Warning/g' data.txt
- 解释: 两个命令按顺序在每一行上执行。
- 命令 (使用分号):
场景 5: 插入和追加文本 (i
, a
)
i
(insert): 在匹配行的 上方 插入文本。a
(append): 在匹配行的 下方 追加文本。
-
任务: 在文件的第一行之前插入一行 "# File managed by Sed script"。
- 命令:
sed '1i # File managed by Sed script' data.txt
- 解释:
1
是行地址,i
表示插入,后面是插入的文本。
- 命令:
-
任务: 在包含 "[Server]" 的那一行之后追加一行 "EnableKeepAlive=true"。
- 命令:
sed '/\[Server]/a EnableKeepAlive=true' data.txt
- 解释:
/\[Server]/
是地址,a
表示追加,后面是追加的文本。
- 命令:
场景 6: 修改整行 (c
)
c
(change) 命令会用新文本替换掉整个匹配的行。
- 任务: 将包含 "DebugMode=false" 的整行替换为 "DebugMode=true # Enabled for testing"。
- 命令:
sed '/DebugMode=false/c DebugMode=true # Enabled for testing' data.txt
- 解释:
/DebugMode=false/
是地址,c
表示替换整行,后面是新的行内容。
- 命令:
场景 7: 文件内编辑 (-i
)
警告: -i
会直接修改原始文件!请务必小心,最好先进行测试。
- 任务: 直接在
data.txt
文件中,将所有 "bob" 替换为 "robert",并创建一个备份文件data.txt.bak
。- 命令:
sed -i.bak 's/bob/robert/g' data.txt
- 解释:
-i.bak
表示进行原地编辑,并在编辑前将原始文件备份为data.txt.bak
。如果只想原地编辑不备份(不推荐),则只用-i
。
- 命令:
总结与建议
- 从简单的打印 (
p
with-n
) 和删除 (d
) 开始,熟悉行地址的概念(数字、正则表达式、范围)。 - 重点掌握替换 (
s
) 命令,它是sed
的核心。练习不同的查找模式、替换字符串和标志 (g
)。注意特殊字符的转义。 - 理解
sed
默认逐行处理并输出到标准输出的模式。 - 谨慎使用
-i
进行原地编辑,优先使用备份-i.bak
。 - 尝试组合使用地址和命令,例如
/pattern/ s/.../.../
。 - 利用分号
;
或-e
执行多个命令。 sed
的正则表达式默认是基本正则表达式 (BRE)。某些特性(如+
,?
,|
)需要转义 (\+
,\?
,\|
) 或使用-E
选项启用扩展正则表达式 (ERE)(GNU sed)。
现在,你可以在你的电脑上打开终端,创建 data.txt
文件,然后逐一执行上面的命令,观察输出结果。修改命令进行试验,这是最好的学习方式!祝你学习顺利!