sed 工具详解
引言
在实际工作当中,我们针对数据分析这块,我们难免会使用到sed的这个工具,那么sed是什么呢?
sed(Stream Editor,流式编辑器)是 Unix/Linux 生态中经典的非交互式文本处理工具,作为类 Unix 系统标准工具集的核心组件,它专为命令行环境下的文本转换、编辑与批量处理设计。sed 摒弃了交互式编辑的冗余操作,以逐行流式处理为核心机制,搭配简洁的编辑命令和强大的正则匹配能力,成为开发、运维场景中日志分析、数据清洗、文件批量修改的必备工具,与 grep、awk 并称为 Linux 文本处理三剑客。
sed 脱胎于 Unix 系统中的 ed 交互式编辑器,最早由 Lee E. McMahon 于 1973 年开发。其核心设计理念是逐行读取、即时处理、逐行输出的流式处理原则:它从输入流(文件、管道传输、标准输入)中逐行读取文本数据,将单行内容加载至临时的 “模式空间” 中,按预设的编辑命令完成处理后,立即将结果输出到标准输出流,同时释放该行为占用的内存资源。简洁高效的处理能力和支持命令组合、正则匹配、脚本化执行的高度可拓展性以及低内存占用的特性,也是 sed 区别于传统交互式编辑器的核心特征。
sed 的核心功能特性
sed 的文本处理能力围绕编辑命令展开,支持单个命令执行或多命令组合,同时深度兼容正则表达式,可通过模式匹配精准定位目标文本,覆盖了命令行环境下几乎所有的文本处理场景。其核心功能特性可分为八大类,每类功能均搭配实用示例,直观体现其使用方式:
流式编辑
流式编辑是 sed 的底层核心特性,也是其区别于其他编辑器的关键,以行为最小处理单元,逐行读取、处理、输出文本,全程无需加载完整文件到内存,内存占用极低,处理大文件时效率优势尤为显著。
# 将Hello, world!中的world替换为John
echo "Hello, world!" | sed 's/world/John/'
输出:
Hello, John!
多编辑命令组合执行
sed 通过专属编辑命令指定对文本的操作,支持单命令执行和多命令组合执行,多个命令通过分号;分隔,按顺序对同一行文本执行连续操作,无需多次调用 sed 工具,简化复杂文本处理的流程,实现 “一行命令完成多步操作”。
# 先替换world为John,再替换Hello为Hi
echo "Hello, world!" | sed 's/world/John/;s/Hello/Hi/'
输出:
Hi, John!
原生正则表达式支持
正则表达式是 sed 实现复杂模式匹配的核心,sed 原生兼容正则语法,可通过正则表达式实现文本的模糊匹配、范围匹配、精准定位,突破普通字符精准匹配的局限,轻松处理不规则、复杂格式的文本。
# 用正则匹配a开头到最后一个e结尾的字符,将apple替换为orange
echo "apple banana" | sed 's/a.*e/orange/'
输出:
orange banana
精准文本替换与行删除
sed 支持对匹配的文本进行指定次数替换,也可根据匹配条件删除指定行,实现精细化的文本编辑,避免对文本进行无差别修改,提升处理的精准度。
# 将第2个apple替换为orange,其余保持不变
echo "apple apple apple" | sed 's/apple/orange/2'
输出:
apple orange apple
地址定位选择操作行
sed 提供地址定位功能,可通过行号、正则表达式匹配、连续行范围等方式,精准选择需要执行编辑操作的行,仅对目标行应用预设命令,其余行保持原样输出,适用于对指定范围文本的修改。
# 定位从包含2的行到包含3的行,将该范围内的Line替换为Number
echo -e "Line 1\nLine 2\nLine 3" | sed '/2/,/3/s/Line/Number/'
输出:
Line 1
Number 2
Number 3
本地文件批量处理
sed 可直接读取本地文件作为输入源,批量处理文件内的所有文本内容,结合重定向符号>可将处理结果保存至新文件,完美适配大批量文件的统一修改、格式转换、内容清洗等需求。
# 将file.txt中的所有apple替换为orange,结果保存到output.txt中
sed 's/apple/orange/' file.txt > output.txt
原始文件原地编辑
通过-i选项,sed 可实现对原始文件的原地编辑,将编辑结果直接保存到原文件中,无需将结果输出到标准输出流再通过重定向生成新文件,大幅简化文件修改的流程
# 直接在file.txt中替换所有apple为orange,覆盖原文件内容
sed -i 's/apple/orange/' file.txt
命令行与脚本化双模式使用
sed 支持命令行直接调用和脚本文件执行两种使用模式:简单操作可直接在命令行输入命令完成;当需要执行的编辑命令较多时,可将所有命令写入 sed 脚本文件,通过-f选项调用脚本,实现命令的复用和复杂文本处理的批量执行。
# 1. 创建脚本文件script.sed,写入编辑命令
echo 's/apple/orange/' > script.sed
# 2. 调用脚本处理file.txt
sed -f script.sed file.txt
sed的基本正则表达式
sed 默认使用基本正则表达式(Basic Regular Expression,BRE) 作为模式匹配的语法,它提供了一组基础、实用的模式匹配规则,可满足绝大多数常规的文本匹配、替换、删除、打印等需求,是使用 sed 进行基础文本处理的必备语法。
BRE 的语法规则严谨,部分特殊元字符需要通过反斜杠转义才能发挥作用,其核心特性可分为字符匹配、字符类、重复匹配、锚定、分组和引用五大类,每类特性均搭配具体的表达式示例和功能描述。
字符匹配
字符匹配是 BRE 最基础的匹配方式,用于匹配单个字符或对特殊字符进行转义,是所有正则匹配规则的基础,支持普通字符、点号、反斜杠三种核心匹配方式:
- 普通字符:表达式中的普通字符与目标文本中的对应字符精准匹配;示例:
sed 's/cat/dog/',将文本中的cat精准替换为dog。 .(点号):匹配除换行符外的任意一个字符;示例:sed 's/c\.t/dog/'',匹配cat、cot、cut等格式的字符并替换为dog。\(反斜杠):转义符,让特殊字符失去原有含义,变为普通字符;示例:sed 's/c.t/dog/',仅匹配文本中的c.t并替换为dog。
字符类
字符类通过方括号[]定义字符集合,实现对多个字符的批量模糊匹配,支持正向字符类和反向字符类两种形式,可快速匹配指定范围内的字符或排除指定字符:
[](方括号):匹配括号内的任意一个字符;示例:sed 's/[aeiou]/X/',将文本中的任意一个元音字母替换为X。[^](反向字符类):匹配不在括号内的任意一个字符;示例:sed 's/[^0-9]/X/',将文本中的任意一个非数字字符替换为X。
重复匹配
重复匹配用于指定某个字符或表达式的匹配次数,是实现多字符连续匹配的核心,BRE 中所有次数限定符均需加反斜杠转义,支持零次 / 多次、一次 / 多次、零次 / 一次、精准次数、范围次数五种匹配方式:
\*(星号):匹配前面的元素零次或多次;示例:sed 's/ab\*c/dog/',匹配ac、abc、abbc等并替换为dog。\+(加号):匹配前面的元素一次或多次;示例:sed 's/ab\+c/dog/',匹配abc、abbc等并替换为dog,不匹配ac。\?(问号):匹配前面的元素零次或一次;示例:sed 's/ab\?c/dog/'',匹配ac、abc并替换为dog,不匹配abbc。 -\{n\}:匹配前面的元素恰好 n 次;示例:sed 's/a\{3\}/dog/',将文本中连续的三个a替换为dog。\{n,m\}:匹配前面的元素至少 n 次,最多 m 次;示例:sed 's/a\{2,4\}/dog/',将文本中连续 2-4 个a替换为dog。
锚定
锚定用于定位文本的行首、行尾、单词边界,实现对文本位置的精准匹配,避免出现部分字符的无效匹配,是实现 “按位置匹配” 的核心特性,支持行首、行尾、单词边界三种锚定方式:
^(脱字符):匹配行的开头;示例:sed '/^abc/d',删除文本中以abc开头的行。$(美元符号):匹配行的结尾;示例:sed '/xyz$/d',删除文本中以xyz结尾的行。\<、\>:匹配单词边界;示例:sed 's/\<apple\>/banana/g' file.txt,将文件中的独立单词apple替换为banana,不匹配applepie等组合词。
分组和引用
分组和引用用于实现多字符的整体匹配和匹配内容的复用,是实现复杂文本替换的重要特性,BRE 中分组符号需要加反斜杠转义,核心包含分组和引用两个部分:
\(\):分组符号,将括号内的表达式作为一个整体单元进行匹配;\n:引用符号,在替换操作中引用之前创建的分组,n为数字,表示引用第 n 个分组的内容。
示例:sed 's/\(abc\)\(def\)/\2\1/',将匹配到的abcdef中的两个分组交换位置,替换为defabc。
标准化字符组表达式
标准化字符组以[[:xxx:]]形式呈现,语义更清晰、跨平台兼容性更强,可替代手动字符集合,该语法为 POSIX 通用标准,BRE 与 ERE 均可直接使用,核心常用字符组如下。
[[:alpha:]]:匹配字母字符(包括大小写字母),等价于[a-zA-Z];示例:sed 's/[[:alpha:]]/X/g' file.txt,替换文本中的字母字符为 X。[[:digit:]]:匹配数字字符,等价于[0-9];示例:sed 's/[[:digit:]]/0/g' file.txt,替换文本中的数字字符为 0。[[:alnum:]]:匹配字母和数字字符,等价于[a-zA-Z0-9];示例:sed 's/[[:alnum:]]/#/g' file.txt,替换文本中的字母和数字字符为 #。[[:space:]]:匹配空白字符集合,包括空格、制表符、换行符、回车符、换页符、垂直制表符,等价于[\t\n\r\f\v ];示例:sed 's/[[:space:]]/,/g' file.txt,替换文本中的空白字符为逗号。[[:word:]]:GNU 扩展单词字符类,等价于[a-zA-Z0-9_](字母 + 数字 + 下划线);示例:sed 's/[[:word:]]/*/g' file.txt,替换文本中的单词字符为 *。
sed的扩展正则表达式
扩展正则表达式(Extended Regular Expression,ERE)是基本正则表达式(BRE)的增强扩展形式,核心新增+/?/|/()四类无需转义的元字符,匹配能力更强大、语法更简洁,广泛应用于 grep、sed、awk、Perl 等各类文本处理工具和编程语言中。
sed 中默认不启用 ERE,需通过-E选项(部分 GNU sed 版本支持-r选项)明确指定,它与 BRE 的核心区别体现在功能特点、语法元素和使用方式三个方面:
功能特点区别
ERE 完全兼容 BRE 基础语法,核心优化是简化元字符转义规则,新增逻辑或匹配,覆盖了 BRE 需转义才能实现的高级匹配需求,让复杂模式匹配更简单。 新增核心元字符:无需转义即可直接使用,实现逻辑或、精准分组等高级功能
+:匹配前一个元素一次或多次(替代 BRE 的+);示例:sed -E 's/foo+bar/baz/' file.txt,匹配foobar、fooobar等并替换为baz。?:匹配前一个元素零次或一次(替代 BRE 的?);示例:sed -E 's/foo(bar)?/baz/' file.txt,匹配foo、foobar并替换为baz。|:逻辑或操作,匹配多个模式中的任意一个;示例:sed -E '/foo|bar/d' file.txt,删除文件中包含foo或bar的行。():分组符号,无需转义(替代 BRE 的());示例:sed -E 's/(foo)(bar)/\2\1/' file.txt,将foobar替换为barfoo。{}:次数限定符,无需转义(替代 BRE 的{});示例:sed -E 's/foo{2,4}/bar/' file.txt,匹配连续 2-4 个o的foo序列并替换为bar。
GNU 扩展转义字符(sed 专属增强语法):丰富模式匹配的类型,提升复杂文本的匹配精准度。
\b:匹配单词边界,与 BRE 的\</\>功能一致;示例:sed -E 's/\btest\b/replacement/' file.txt,将文件中的独立单词test替换为replacement。\s:匹配任意空白字符(空格、制表符、换行符等);示例:sed -E 's/\s//g' file.txt,删除文件中的所有空白字符。\w:匹配任意字母数字字符和下划线(等价于[a-zA-Z0-9_]);示例:sed -E 's/\w/*/g' file.txt,将文件中的字母、数字、下划线替换为*。
语法元素区别
ERE 的核心优化之一是简化转义规则,减少了不必要的反斜杠使用,让正则表达式的编写更简洁,与 BRE 的转义规则形成鲜明对比:
- ERE 中,
+、?、|、(、)、{}等元字符无需加反斜杠转义,可直接使用其特殊功能; - ERE 中,
{}内的逗号,无需转义,直接写为{n,m}即可表示次数范围;
sed命令使用区别
sed 中 BRE 和 ERE 的编辑命令逻辑完全一致,二者的唯一区别在于启用选项,使用规则简单易懂,具体对比如下:
- 使用 BRE:默认方式,无需添加任何额外选项,元字符和语法元素需严格按照 BRE 规则进行转义;示例:
sed 's/ab\+c/dog/' file.txt(加号需转义)。 - 使用 ERE:必须通过
-E选项明确指定,元字符和语法元素无需转义,可直接使用;示例:sed -E 's/ab+c/dog/' file.txt(加号直接使用)。