Linux 中的 sed 命令及示例

Linux 中的 sed 命令是一个流编辑器,无需打开编辑器即可转换文件或管道中的文本。与将整个文件加载到内存中并需要交互式输入的传统编辑器不同,sed 逐行处理文本,应用您指定的命令并立即输出结果。这一设计使其非常适合脚本、数据管道以及注重速度和精度的一次性命令行任务中的自动文本处理。

本指南涵盖了从在最小图像上安装 GNU sed 到理解模式和保留空间缓冲区、应用地址范围、使用循环和分支编写脚本以及将 sed 与其他 Unix 工具链接以实现实际自动化的所有内容。跟随练习选择性打印、删除、插入、文件读取和写入、多行操作以及处理日志、CSV 数据、配置文件和部署工作流程的可重用 sed 脚本。

Sed 融入了日常工作流程,因为它从管道中读取数据,尊重自动化,并且无需额外工具即可跨发行版可靠地工作。它还提供的功能远不止基本替换,还可以在同一个轻量级二进制文件中处理选择性打印、行插入、多行转换和文件 I/O。

  • 系统管理员提取目标日志条目、过滤配置片段、重新编号文档以及在庞大的目录中自动进行批量编辑。
  • 开发商将 sed 连接到构建管道中以注入版本字符串、在部署之前删除注释或在打包期间重塑配置模板。
  • 数据分析师将 sed 与其他 CLI 工具链接起来,以清理 CSV 导出、规范化分隔符并隔离字段,而无需使用更繁重的脚本语言。

如果您特别需要深入了解在文件中查找和替换字符串,包括处理特殊字符、使用分隔符以及解决跨平台差异,请参阅我们的专用。本文重点介绍更广泛的 sed 命令功能:打印特定行、删除模式、插入和附加文本、使用地址范围、多行操作、保留空间和模式空间操作、读写文件以及为复杂的自动化任务构建可重用的 sed 脚本。

了解 sed 命令

如果您不熟悉 sed,请将其视为命令行文本处理器,逐行读取输入,应用您指定的转换规则,并输出结果。与在编辑器中打开文件不同,sed 处理文本流,使其非常适合数据从一个命令流向另一个命令而无需创建临时文件的管道。

基本语法

具体来说,基本语法遵循以下模式:

sed [OPTIONS] 'COMMAND' [INPUT-FILE]

分解每个组件:

  • 选项:修改 sed 行为的标志,例如-i对于就地编辑,-n用于抑制自动输出,或-E用于扩展正则表达式。这些是可选的并且可以组合(例如,-n -i.bak)。
  • 命令:要应用的转换,用单引号括起来以保护它免受 shell 解释。命令可以很简单,例如'd'删除行,或复杂的像's/old/new/g'用于全球替代。您可以使用分号链接多个命令:'s/foo/bar/; /error/d'
  • 输入文件:要处理的文件。如果省略,sed 从标准输入 (stdin) 读取,允许您从其他命令传输数据,例如cat file.txt | sed 's/foo/bar/'或者curl https://example.com | sed '/ads/d'

sed 如何处理文本

Sed 使用两个缓冲区进行操作,这两个缓冲区确定文本如何流经编辑器:

  • 图案空间:sed 存储当前正在处理的行的工作缓冲区。默认情况下,您编写的每个 sed 命令都在模式空间上运行。当 sed 读取新行时,它会用该行替换模式空间内容(除非您使用类似的命令N附加到它)。
  • 保留空间:在行之间保留的辅助存储缓冲区。您可以使用以下命令在模式空间和保持空间之间复制或交换数据h(抓住),g(得到),并且x(交换)。这使得复杂的操作成为可能,例如反转文件、跨行累积数据或实现条件逻辑。

工作流程周期

一般来说,典型的 sed 工作流程遵循以下循环:

  1. 从输入读取一行到模式空间
  2. 在模式空间上执行命令(替换、删除、变换等)
  3. 打印模式空间(除非-n抑制它或命令删除它)
  4. 移至下一行并重复

例如,sed 's/Linux/Unix/' file.txtfile.txt逐行将每行中第一次出现的“Linux”替换为“Unix”,并将结果打印到终端而不更改原始文件。模式空间一次保存一行,替换命令会修改它,并且 sed 在移动到下一个输入行之前自动打印修改后的行。

此外,以下是按任务组织的最有用的选项和命令:

Sed 命令参考表

文本替换

任务选项/命令它的作用
替换每行的第一个匹配项s/pattern/replacement/将每行中第一次出现的“pattern”替换为“replacement”
替换每行的所有匹配项s/pattern/replacement/ggflag 使替换全局,替换每一个出现的地方

删除操作

任务选项/命令它的作用
删除匹配行/pattern/d删除包含“pattern”的整行
删除特定行号'3d'或者'5,10d'删除第 3 行或第 5 至 10 行
删除空行'/^$/d'从输出中删除所有空行

打印和输出控制

任务选项/命令它的作用
打印特定行-n '5p'或者-n '10,20p'仅打印第 5 行或第 10 至 20 行(需要-n旗帜)
打印匹配行-n '/pattern/p'仅显示包含“pattern”的行(类似于 grep)
抑制自动输出-n仅在明确告知时才打印行p命令

插入和追加

任务选项/命令它的作用
在行前插入文本/pattern/i\text在与“模式”匹配的行之前插入“文本”
在行后附加文本/pattern/a\text在匹配“模式”的行之后附加“文本”

行寻址

任务选项/命令它的作用
适用于特定线路'5s/old/new/'仅在第 5 行替换
适用范围'10,20s/old/new/'第 10 行到第 20 行的替换
适用于图案范围'/start/,/end/d'删除从第一个“开始”匹配到第一个“结束”匹配的行
否定地址'/pattern/!d'删除所有不匹配“模式”的行

多线操作

任务选项/命令它的作用
将下一行追加到模式空间N读取下一行并使用换行符附加到当前模式空间
打印图案空间的第一行P打印模式空间中的第一个换行符(对于N
删除模式空间的第一行D删除直到第一个换行符并重新开始循环而不读取新行

保留空间操作

任务选项/命令它的作用
复制模式空间到保留空间h用模式空间内容覆盖保留空间
追加模式空间以保存空间H附加模式空间以保留带有换行符分隔符的空间
将保留空间复制到模式空间g用保留空间内容覆盖模式空间
将保留空间附加到模式空间G使用换行分隔符将保留空间附加到模式空间
交换缓冲区x交换模式空间和保留空间内容

文件操作

任务选项/命令它的作用
就地编辑文件-i修改原始文件而不是打印到标准输出
读取文件并插入r filename从文件中读取内容并将其插入到当前行之后
写入文件w filename将模式空间写入文件(如果文件存在则追加)
使用脚本文件-f script.sed从文件而不是命令行读取 sed 命令

高级功能

任务选项/命令它的作用
链接多个命令-e 'cmd1' -e 'cmd2'按顺序应用多个转换
使用扩展正则表达式-E启用扩展正则表达式(需要更少的转义)
退出处理q在当前行之后立即退出 sed
变换字符y/abc/xyz/音译字符(类似于tr命令)
打印行号=在行内容之前打印当前行号

因此,“抑制自动输出”行为-n意味着 sed 默认情况下不会打印每一行。通常,sed 打印所有输入行(无论是否更改),但是-n关闭此行为,以便您可以使用p命令。当您想要提取特定行而不是转换整个文件时,这一点至关重要。

在流行的 Linux 发行版上安装 sed

GNU sed 几乎随每个主流 Linux 发行版一起提供,但最小的容器或精简的映像可能会忽略它。首先验证可用性,然后安装添加全功能 GNU sed 二进制文件的软件包(如果缺少)。

检查 sed 是否已经存在:

sed --version

如果未找到该命令,请使用您的发行版的包管理器:

基于 Ubuntu 和 Debian 的发行版:

sudo apt update
sudo apt install sed

Fedora、RHEL、Rocky Linux 和 AlmaLinux:

sudo dnf install sed

Arch Linux 和 Manjaro:

sudo pacman -S sed

开放SUSE:

sudo zypper install sed

阿尔卑斯Linux:

sudo apk add sed

包名称是sed跨这些发行版,因此上面的命令安装支持本指南中使用的功能的 GNU 实现。

Linux 中 Sed 命令的基本示例

示例 1:基本文本替换

文本替换是 sed 最受认可的操作,尽管远非它唯一的功能。此示例演示了转向 sed 更广泛的功能集之前最简单的形式:

echo "Welcome to Linux" | sed 's/Linux/Unix/'

输出:

Welcome to Unix

有关查找和替换操作的全面介绍,包括全局替换、不区分大小写的匹配、处理特殊字符、分隔符选择和备份就地编辑,请参阅我们的专用文档其中深入涵盖了替换操作。

示例 2:打印特定行

此外,-n选项与p命令允许您提取特定行而不修改它们。当您需要查看日志文件、配置文件或数据导出的特定部分时,这非常有用。

首先,显示文件中的第 5 行:

sed -n '5p' /var/log/syslog

接下来,拉出第 10 行到第 20 行:

sed -n '10,20p' /etc/services

最后,显示与模式匹配的行(类似于 grep):

sed -n '/error/p' application.log

-nflag 抑制 sed 打印每一行的默认行为,因此只有明确标记为p出现在输出中。没有-n,您将看到所有行以及匹配行的重复项。

示例 3:删除行

实际上,在处理日志文件或数据导出时,您经常需要删除与特定模式匹配的行。塞德的d命令从输出流中删除行而不修改源文件。

首先,删除包含“debug”的每一行:

sed '/debug/d' application.log

然后清除所有空白行:

sed '/^$/d' messy-file.txt

之后,删除第 5 行到第 10 行:

sed '5,10d' data.csv

最后,剪切从特定标记到文件末尾的所有内容:

sed '/START_OF_FOOTER/,$d' document.txt

d命令从模式空间中完全删除匹配的行,防止它们到达输出。美元符号 ($地址范围中的 ) 表示输入的最后一行。

示例 4:插入和附加文本

同样,通过在特定模式之前或之后添加行,您可以将标头注入数据文件、向配置部分添加注释或插入时间戳,而无需手动编辑每个文件。

在模式之前插入文本:

sed '/^database_settings/i\# Database Configuration' config.ini

在模式后附加文本:

sed '/^server {$/a\    # Server block configuration' nginx.conf

插入多行(使用文字换行符):

sed '/pattern/i\First line\
Second line\
Third line' file.txt

i命令在匹配行之前插入,而a追加在其后。这两个命令都将新文本放置在输出流中,而不修改现有行的模式空间内容。

示例 5:使用 Transform 更改文本大小写

同样,y命令音译字符,类似于tr命令。这在标准化数据以进行比较、标准化输入格式或为区分大小写的系统准备文本时非常有用。

将小写转换为大写:

echo "hello world" | sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'

输出:

HELLO WORLD

转换特定字符:

echo "a-b-c-d" | sed 'y/-/_/'

输出:

a_b_c_d

y命令将第一组中的每个字符映射到第二组中的相应字符。两个集合必须包含相同数量的字符,并且转换适用于模式空间中的每个匹配字符。

示例 6:打印行号

同样,=命令打印当前行号,这有助于调试 sed 脚本、识别大文件中的行位置或创建编号列表。

打印所有行的行号:

printf "apple\nbanana\ncherry\n" | sed '='

输出:

1
apple
2
banana
3
cherry

仅打印匹配行的行号:

sed -n '/error/=' application.log

=命令在模式空间内容之前在其自己的行上输出行号,因此您可以在下一行看到数字后跟实际文本。

Linux 中 Sed 命令的高级用法

示例 7:地址范围和线路选择

此外,sed 的寻址系统允许您将命令应用于特定行、行范围或匹配模式的行。在编辑配置文件(其中更改仅影响特定部分)时,或者在处理需要提取或修改特定时间范围的日志文件时,这种精度至关重要。

定位特定行号

sed '3s/old/new/' file.txt

对一系列行号进行操作

sed '10,20s/DEBUG/INFO/' application.log

匹配由两个模式定义的范围

sed '/<configuration>/,/<\/configuration>/s/enabled="false"/enabled="true"/' config.xml

从特定行到文件末尾的处理

sed '100,$d' large-file.txt

否定地址

sed '/^#/!d' script.sh

最后一个示例仅保留注释行(以#)通过删除其他所有内容。感叹号否定地址,因此删除命令适用于与模式不匹配的所有行。

示例8:多行操作

此外,多行命令允许您使用文本块而不是单独的行。当处理逻辑单元跨越多行的数据格式(例如配置块、代码函数或跨行分割的数据记录)时,这一点至关重要。

将行连接到单个记录中

printf "line one\nline two\nline three\n" | sed 'N;s/\n/ /'

输出:

line one line two
line three

N命令使用换行符分隔符将下一行追加到模式空间,然后替换将该换行符替换为空格。 sed 以这种方式处理行对,连接每两个连续行。

折叠多个空行

sed '/^$/{N;/^\n$/d;}' file-with-blank-lines.txt

跨行边界匹配模式

printf "Error:\nConnection timeout\n" | sed 'N;s/Error:\nConnection/Error: Network connection/'

输出:

Error: Network connection timeout

在重新格式化代码、合并配置文件中的连续行或处理字段值跨越多行的数据导出时,多行操作特别有用。

示例 9:保持空间和模式空间

此外,保持空间充当用于存储行间数据的辅助缓冲区。这可以实现复杂的转换,例如反转文件顺序、跨多行累积数据或基于先前内容实现条件逻辑。

颠倒行的顺序

printf "first\nsecond\nthird\n" | sed -n '1!G;h;$p'

输出:

third
second
first

这种方法的工作原理是:(1) 对于除第一行之外的所有行,将保留空间附加到模式空间G, (2) 将模式空间复制到保存空间h, (3) 在最后一行 ($),打印累计结果。每个新行都会添加到保留空间中累积的内容之前,从而有效地反转顺序。

检测连续重复项

printf "apple\napple\nbanana\nbanana\nbanana\ncherry\n" | sed -n 'N;/^\(.*\)\n\1$/p;D'

该命令一次读取两行,当两行匹配时打印它们,然后重新开始循环,这样每对只能看到一次连续的重复项。

每两行交换一次

printf "line1\nline2\nline3\nline4\n" | sed 'N;s/\(.*\)\n\(.*\)/\2\n\1/'

输出:

line2
line1
line4
line3

当您需要跨行维护状态(例如跟踪节标题、累加总数或将当前行与前一行进行比较)时,保留空间操作就变得至关重要。

示例 10:读写文件

此外,sed 可以从外部文件读取内容并将其插入到输出流中,或将模式空间的部分写入单独的文件。这可以实现强大的工作流程,例如将模板与数据合并、根据模式拆分文件或在处理过程中动态构建文件。

在匹配行后插入文件内容

echo "This is a header." > header.txt
printf "Section 1\nContent here\nSection 2\nMore content\n" | sed '/^Section/r header.txt'

输出:

Section 1
This is a header.
Content here
Section 2
This is a header.
More content

r命令读取整个文件并将其插入到与模式匹配的每一行之后。这对于在特定点注入通用页眉、页脚或模板内容非常有用。

将匹配的行写入单独的文件

sed -n '/ERROR/w errors.log' application.log

根据模式分割文件

sed '/^INFO/w info.log
/^WARN/w warnings.log
/^ERROR/w errors.log' mixed.log

w命令将模式空间附加到指定的文件。如果该文件不存在,sed 将创建它;如果存在,sed 将附加到它。这使您可以在一次传递中过滤输入的不同部分并将其路由到不同的目的地。

示例 11:使用 Sed 脚本文件

每当 sed 命令变得复杂或者您需要在多个文件中重用相同的转换时,将命令放入脚本文件中可以使它们更易于维护和共享。这-f选项从文件而不是命令行读取命令。

创建一个 sed 脚本文件:

cat > cleanup.sed <<'EOF'
# Remove blank lines
/^$/d

# Remove comments
/^#/d

# Convert tabs to spaces
s/\t/    /g

# Trim trailing whitespace
s/[[:space:]]\+$//
EOF

将脚本应用到文件:

sed -f cleanup.sed messy-config.txt

脚本文件支持注释(以#)并且可以根据需要包含任意多个命令,每行一个。脚本文件中的命令按顺序执行,就像在命令行上用分号将它们链接起来一样。

将相同的脚本应用于多个文件:

find . -name "*.conf" -exec sed -i.bak -f cleanup.sed {} +

这种方法将您的转换逻辑保留在一个位置,从而更轻松地进行版本控制、记录和跨项目一致应用。

示例 12:条件执行和分支

类似地,sed 支持条件执行,使用b(分行)和t(测试)命令。这些使您可以在 sed 脚本中创建复杂的逻辑流,实现 if-then-else 模式或循环,而无需调用完整的脚本语言。

跳过注释行的处理:

sed '/^#/b; s/old/new/g' config.txt

此分支(跳转到脚本的末尾)以开头的行#,有效地跳过注释的替换命令。

应用多次替换,直到不再发生更改:

echo "aaabbbccc" | sed ':loop; s/aa/a/g; t loop'

输出:

abbbccc

:loop创建一个标签,并且t loop如果先前的替换成功,则分支回该标签。这会创建一个不断替换的循环aaa直到不再有aa序列存在。

示例 13:使用 q 提前退出

反过来,q命令在处理完当前行后立即退出 sed。当您只需要处理大文件的开头(例如提取标头或在找到特定模式后停止)时,这可以提高性能。

仅打印前 10 行(例如head -10):

sed '10q' large-logfile.log

找到模式后停止处理:

sed '/^ERROR/q' application.log

提取所有内容直至标记:

sed '/^---END OF HEADER---$/q' document.txt

q命令打印当前行(除非您使用-n)然后立即退出,通过避免对剩余内容进行不必要的处理来节省处理大文件的时间。

现实世界的实际例子

示例 14:处理日志文件

由于日志文件分析通常需要提取特定条目、消除噪音或重新格式化时间戳,因此 sed 可以有效地处理这些任务,而无需将整个文件加载到内存中。

首先仅提取错误和警告消息:

sed -n '/ERROR\|WARN/p' application.log

接下来,删除调试和跟踪消息:

sed '/DEBUG\|TRACE/d' verbose.log > clean.log

然后隔离特定时间范围内的日志:

sed -n '/2025-11-06 14:00/,/2025-11-06 15:00/p' timestamped.log

最后,将行号添加到错误消息中以便于调试:

sed -n '/ERROR/{=;p;}' application.log | sed 'N;s/\n/: /'

示例 15:CSV 和数据文件操作

同样,sed 擅长清理和转换 CSV 文件或其他分隔数据格式。您可以提取列、重新排序字段或标准化不一致的格式,而无需将数据加载到电子表格软件中。

从 CSV 数据中提取第二列:

echo "Name,Age,City\nJohn,30,NYC\nJane,25,LA" | sed 's/^[^,]*,\([^,]*\).*/\1/'

输出:

Age
30
25

从 CSV 中删除标题行:

sed '1d' data.csv > data-no-header.csv

将逗号分隔转换为制表符分隔:

sed 's/,/\t/g' data.csv > data.tsv

从带引号的 CSV 字段中删除引号:

sed 's/"//g' quoted.csv > unquoted.csv

示例 16:配置文件更新

对于运营团队来说,自动化配置管理依赖于 sed 等工具来修改设置,而无需手动编辑。这在配置服务器、在部署期间更新应用程序设置或跨环境维护一致的配置时尤其有价值。

更改配置值:

sed -i 's/^max_connections = .*/max_connections = 200/' postgresql.conf

启用注释掉的设置:

sed -i 's/^# *\(listen_addresses\)/\1/' postgresql.conf

一次性更新多个相关设置:

sed -i -e 's/old_server/new_server/' \
       -e 's/port=3306/port=3307/' \
       -e 's/timeout=30/timeout=60/' database.ini

在特定节标题后添加新设置:

sed -i '/^\[database\]$/a\new_option = value' config.ini

示例 17:代码和文档处理

在 macOS 或其他基于 BSD 的系统上,sed -i需要一个备份后缀。使用sed -i '' 's/pattern/replacement/' file就地编辑而不留下备份文件,或提供显式后缀,例如-i .bak

开发人员经常在构建管道中使用 sed 来注入版本字符串、删除生产代码的注释或转换文档格式。这些操作无缝集成到自动化工作流程中。

从代码中删除单行注释:

sed '/^[[:space:]]*\/\//d' source.js > clean-no-comments.js

这会删除独立的//注释行不触及 URL 或其他内联内容,这对于嵌入字符串的源文件来说更安全https://

修剪代码后面的尾随内联注释(假设您的样式在注释前插入一个空格):

sed -E 's#[[:space:]]+//.*$##' source.js > clean-inline-comments.js

该表达式仅删除//序列前面有空格,因此字符串和协议前缀保持不变。如果您的代码库内嵌注释的格式不同,请调整模式。

将构建版本注入源文件:

VERSION="2.4.1"
sed -i "s/VERSION_PLACEHOLDER/$VERSION/" version.h

将 Markdown 标题转换为 HTML:

sed -E 's/^## (.*)$/

\1<\/h2>/' document.md

从源代码中提取函数定义:

sed -n '/^def /p' python_script.py

示例 18:系统管理任务

在日常管理中,系统管理员利用 sed 进行批量用户管理、自动系统配置更新以及处理复杂管道中其他工具的命令输出。

从 /etc/passwd 中提取用户名:

sed 's/:.*$//' /etc/passwd

查找具有特定 shell 的用户:

sed -n '/\/bin\/bash$/p' /etc/passwd

格式化磁盘使用输出以便于阅读:

df -h | sed '1d' | sed 's/\([0-9]\+\)%/[\1%]/'

从列表生成主机文件条目:

cat server-list.txt | sed 's/^/192.168.1./' | sed 's/$/.example.com/'

示例 19:将 Sed 与其他命令组合

最终,当与管道中的其他 Unix 工具结合使用时,sed 的真正威力就会显现出来。这些组合使您可以构建复杂的文本处理工作流程,而这需要使用传统脚本语言编写大量代码。

查找并清理最近的错误日志:

find /var/log -name "*.log" -mtime -1 -exec sed -n '/ERROR/p' {} + | sort | uniq

处理 Web 服务器日志以提取 IP 地址:

cat access.log | sed 's/^\([^ ]*\) .*/\1/' | sort | uniq -c | sort -rn | head -10

该替换存储第一个以空格分隔的字段,因此点分的 IPv4 地址和冒号分隔的 IPv6 地址在排序和计数之前都保持不变。

清理进程列表输出:

ps aux | sed '1d' | sed 's/  \+/ /g' | cut -d' ' -f1,11

提取并格式化包版本:

dpkg -l | sed -n '/^ii/p' | sed 's/  \+/ /g' | cut -d' ' -f2,3

结论

总体而言,sed 命令为 Linux 中几乎所有文本处理任务提供快速、可编写脚本的文本转换。通过了解模式空间和保留空间缓冲区、掌握地址范围和多行操作、使用读写命令进行文件操作、利用 sed 脚本文件实现复杂的可重用工作流程,以及了解如何将 sed 与管道中的其他 Unix 工具链接起来,您可以自信地自动执行从简单的行删除到复杂的多文件转换的文本处理任务。有关文本替换操作的深入介绍,请参阅我们的配套指南。