跳到主要内容

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) 命令结合使用,只打印我们明确指定的行。

  1. 任务: 打印文件的第 3 行。

    • 命令:
      sed -n '3p' data.txt
    • 解释: -n 禁止默认输出,3 是行地址,p 是打印命令。只打印第 3 行。
  2. 任务: 打印文件的第 5 行到第 8 行。

    • 命令:
      sed -n '5,8p' data.txt
    • 解释: 5,8 是行地址范围,打印这个范围内的行。
  3. 任务: 打印所有包含 "ERROR" 的行。

    • 命令:
      sed -n '/ERROR/p' data.txt
    • 解释: /ERROR/ 是一个正则表达式地址,匹配包含 "ERROR" 的行,p 打印匹配行。
  4. 任务: 打印所有以 "#" 开头的行(注释行)。

    • 命令:
      sed -n '/^#/p' data.txt
    • 解释: /^#/ 正则表达式地址,^ 表示行首,# 是要匹配的字符。
  5. 任务: 打印从包含 "[Database]" 的行开始,到第一个空行之间的所有行。

    • 命令:
      sed -n '/\[Database]/,/^$/p' data.txt
    • 解释: /\[Database]/,/^$/ 是一个由两个正则表达式定义的地址范围。[ 需要转义 \[/^$/ 匹配空行。

场景 2: 删除特定行 (行寻址与删除 d)

d (delete) 命令用于删除匹配的行。注意,默认情况下 sed 只是不打印这些行到标准输出,原始文件不变。

  1. 任务: 删除所有空行。

    • 命令:
      sed '/^$/d' data.txt
    • 解释: /^$/ 匹配空行,d 删除匹配的行。
  2. 任务: 删除所有注释行(以 "#" 开头)。

    • 命令:
      sed '/^#/d' data.txt
    • 解释: /^#/ 匹配注释行,d 删除。
  3. 任务: 删除第 10 行。

    • 命令:
      sed '10d' data.txt
    • 解释: 10 是行地址,d 删除第 10 行。
  4. 任务: 删除从第 1 行到第 3 行。

    • 命令:
      sed '1,3d' data.txt
    • 解释: 1,3 是行地址范围,d 删除这个范围内的行。
  5. 任务: 删除所有包含 "DEBUG" 的行。

    • 命令:
      sed '/DEBUG/d' data.txt
    • 解释: /DEBUG/ 匹配包含 "DEBUG" 的行,d 删除。

场景 3: 替换文本 (替换 s)

这是 sed 最常用、最强大的功能。s (substitute) 命令用于查找和替换。

基本语法: s/查找模式/替换字符串/[标志]

常用标志:

  • g: 全局替换 (Global),替换行内所有匹配项,而不仅仅是第一个。
  • i: 忽略大小写 (Ignore case),(GNU sed 特有)。
  1. 任务: 将每行中第一次出现的 "INFO" 替换为 "Information"。

    • 命令:
      sed 's/INFO/Information/' data.txt
    • 解释: s 表示替换。/INFO/ 是查找模式。/Information/ 是替换字符串。默认只替换每行第一个匹配项。
  2. 任务: 将文件中所有的 "user" (小写) 替换为 "account"。

    • 命令:
      sed 's/user/account/g' data.txt
    • 解释: g 标志表示全局替换,替换行内所有出现的 "user"。
  3. 任务: 将数据库密码那一行 (DB_Pass=...) 中的密码替换为 "[REDACTED]"。

    • 命令:
      sed '/^DB_Pass=/ s/=.*/=[REDACTED]/' data.txt
    • 解释: /^DB_Pass=/ 是地址,只在匹配此模式的行上执行后面的 s 命令。s/=.*/=[REDACTED]/ 查找第一个 = 及其之后的所有内容 (.*),并替换为 =[REDACTED]
  4. 任务: 更改数据库主机名 db.example.comprod-db-replica.internal

    • 命令:
      sed 's/db\.example\.com/prod-db-replica.internal/' data.txt
    • 解释: 在查找模式中,. 是正则表达式元字符(匹配任意单个字符),需要用 \ 转义 (\.) 来匹配字面上的点。
  5. 任务: 使用不同的分隔符(例如 #|)进行替换,当查找或替换内容包含 / 时特别有用。例如,更改日志中的 IP 地址 192.168.1.25410.10.0.10

    • 命令:
      sed 's|192\.168\.1\.254|10.10.0.10|' data.txt
    • 解释: 使用 | 作为 s 命令的分隔符,避免了转义 /。仍然需要转义 .
  6. 任务: 只在包含 "ERROR" 的行中,将 "Failed" 替换为 "Attempted"。

    • 命令:
      sed '/ERROR/ s/Failed/Attempted/' data.txt
    • 解释: /ERROR/ 是地址,s 命令只应用于匹配该地址的行。

场景 4: 同时执行多个命令

可以用分号 ;-e 选项来执行多个 sed 命令。

  1. 任务: 删除所有空行,并将 "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): 在匹配行的 下方 追加文本。
  1. 任务: 在文件的第一行之前插入一行 "# File managed by Sed script"。

    • 命令:
      sed '1i # File managed by Sed script' data.txt
    • 解释: 1 是行地址,i 表示插入,后面是插入的文本。
  2. 任务: 在包含 "[Server]" 的那一行之后追加一行 "EnableKeepAlive=true"。

    • 命令:
      sed '/\[Server]/a EnableKeepAlive=true' data.txt
    • 解释: /\[Server]/ 是地址,a 表示追加,后面是追加的文本。

场景 6: 修改整行 (c)

c (change) 命令会用新文本替换掉整个匹配的行。

  1. 任务: 将包含 "DebugMode=false" 的整行替换为 "DebugMode=true # Enabled for testing"。
    • 命令:
      sed '/DebugMode=false/c DebugMode=true # Enabled for testing' data.txt
    • 解释: /DebugMode=false/ 是地址,c 表示替换整行,后面是新的行内容。

场景 7: 文件内编辑 (-i)

警告: -i 会直接修改原始文件!请务必小心,最好先进行测试。

  1. 任务: 直接在 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 文件,然后逐一执行上面的命令,观察输出结果。修改命令进行试验,这是最好的学习方式!祝你学习顺利!