sed
字数: 12920 字 时长: 47 分钟
sed
是一种流式文本编辑器,它是文本处理中非常强大的工具,能够与正则表达式完美结合,实现高效且灵活的文本操作。sed
在处理文本时,会逐行读取输入内容,将当前处理的行存储在临时缓冲区中,这个缓冲区也被称为模式空间(Pattern Space)。随后,sed
会根据指定的命令对模式空间中的内容进行处理。处理完成后,将模式空间中的内容输出到屏幕上,接着读取下一行并重复上述过程,直到处理完文件中的所有行。
默认情况下,sed
不会直接修改原始文件的内容,而是仅对模式空间中的数据进行操作。如果需要修改原始文件,可以通过特定选项(如 -i
)来实现。
流式编辑器
流式(Stream)文本编辑器是指对文本数据进行逐行处理的工具,它将文本视为一个连续的「流」,而不是一次性加载整个文件进行处理。这种处理方式类似于水流一样,逐行读取、处理并输出结果。
sed
的处理流程可以总结为以下步骤:
- 逐行读取:每次仅读取一行内容到模式空间。
- 匹配与修改:根据提供的规则命令对模式空间中的数据进行匹配和修改。需要注意的是,sed 默认不会直接修改源文件数据,而是将数据复制到模式空间中进行操作。
- 输出结果:将模式空间中修改后的数据输出到标准输出(通常是屏幕)。
- 循环处理:处理完当前行后,继续读取下一行并重复上述过程,直到处理完文件中的所有行。
sed
的模式匹配和文本选择功能高度依赖于正则表达式(Regexes),这使得它能够灵活地处理各种复杂的文本模式。通过正则表达式,用户可以精确地指定需要匹配的文本模式,从而实现高效的查找、替换、删除等操作。
基本语法
sed
的基本语法如下:
sed [OPTION]... {script-only-if-no-other-script} [input-file]...
script-only-if-no-other-script
:如果未使用-e
或-f
选项指定其他脚本,则可以在这里直接指定一个sed
脚本。脚本可以是一个简单的命令,也可以是多个命令的组合。input-file
:指定要处理的输入文件。可以同时指定多个文件,sed
会依次处理每个文件。
常用选项 | 描述 |
---|---|
-n | 禁止自动打印模式空间:默认情况下,sed 会自动打印处理后的每一行。使用 -n 选项后,sed 不会自动打印任何内容,只有在脚本中明确使用 p 命令时才会打印指定的行。这在需要精确控制输出时非常有用。 |
-e <script> | 添加脚本到命令中:允许在命令行中直接指定一个或多个 sed 脚本。如果需要执行多个脚本命令,可以多次使用 -e 选项。例如:sed -e 's/a/b/' -e 's/c/d/' 。 |
-f <script-file> | 从文件中读取脚本:指定一个包含 sed 脚本的文件。脚本文件中的命令会逐行执行。这在处理复杂的脚本时非常方便,可以将脚本写入文件中,然后通过 -f 选项调用。 |
-i[SUFFIX] | 直接编辑文件:允许直接修改输入文件,而不是将结果输出到标准输出。如果提供了 SUFFIX,则会创建一个备份文件,备份文件的扩展名为指定的 SUFFIX。例如:sed -i.bak 's/old/new/' file.txt 会将 file.txt 中的内容替换,并创建一个名为 file.txt.bak 的备份文件。 |
-c | 使用复制而不是重命名:在使用 -i 模式时,sed 默认通过重命名文件来实现原地编辑。使用 -c 选项后,sed 会通过复制原始文件来实现备份,而不是重命名。这种方式在某些情况下可以避免文件权限问题。 |
-b | 不执行任何操作:这个选项通常用于测试,它不会对文件进行任何实际操作,但会显示 sed 命令的执行效果。 |
-r 、-E | 使用扩展正则表达式:默认情况下,sed 使用基本正则表达式(BRE)。使用 -r (GNU 扩展)或-E(POSIX 扩展)选项后,可以启用扩展正则表达式(ERE),从而支持更复杂的正则表达式语法。为了确保跨平台兼容性,建议使用 -E 选项。 |
-s | 将文件视为独立的流:默认情况下,sed 将多个文件视为一个连续的长流,这意味着跨文件的模式空间是连续的。使用 -s 选项后,sed 会将每个文件视为独立的流,每个文件的模式空间是独立的。这在处理多个文件时非常有用,可以避免跨文件的模式空间混淆。 |
sed 脚本
sed
脚本是一系列 sed
命令的集合,它们指定了要对输入文本执行的操作。脚本中的每个命令通常由一个字母(如 s
、d
或 p
)和一些参数组成,用于指定操作的类型以及操作的文本范围。通过组合这些命令,sed
可以实现复杂的文本处理任务。
注意,sed
脚本通常需要使用单引号 ''
或双引号 ""
来包裹命令,以确保命令中的特殊字符(如空格、美元符号、反斜杠等)被正确处理。使用单引号 ''
是最常见的做法,因为它可以防止 Shell 对脚本中的内容进行额外的解释。
sed
脚本语法:
[address]command[arguments]
address
:可选的地址范围,用于指定命令作用的行。可以是行号、正则表达式或两者的组合。command
:sed
命令,如p
(打印)、d
(删除)、s
(替换)等。arguments
:命令的参数,具体取决于命令类型。
地址范围(Address):
地址范围用于指定命令作用的行。可以是以下几种形式:
- 行号:指定特定行。例如,1 表示第一行,5 表示第五行。
- 正则表达式:用
/pattern/
表示匹配特定模式的行。例如,/root/
表示匹配包含 root 的行。 - 地址范围:用
M,N
表示从第M
行到第N
行。例如,1,5
表示从第一行到第五行。 - 特殊符号:
$
:表示最后一行;~
:用于指定步长。例如,1~2
表示从第一行开始,每隔一行。
sed
命令:
常用的命令 | 描述 |
---|---|
a | 在当前行下面插入文本:在当前行的下方插入指定的文本。例如,a\Hello 会在当前行的下方插入 Hello。 |
i | 在当前行上面插入文本:在当前行的上方插入指定的文本。例如,i\Hello 会在当前行的上方插入 Hello。 |
c | 替换当前行:将当前行替换为指定的文本。例如,c\New Line 会将当前行替换为 New Line。 |
d | 删除当前行:删除当前行的内容。例如,d 会删除当前行。 |
s | 替换指定字符:这是 sed 最常用的命令之一,用于替换文本中的某些内容。格式为 s/模式/替换内容/ 标志。例如,s/old/new/g 会将每行中的所有 old 替换为 new 。 |
l | 可视化方式打印模式空间中的文本:以可视化方式打印模式空间中的文本,不可打印字符会以反斜杠转义序列的形式显示。例如,l 可以用来查看模式空间中的特殊字符。 |
n | 读取下一行输入:读取下一行输入并将其存储在模式空间中,覆盖当前模式空间的内容。例如,n 可以用于跳过当前行,处理下一行。 |
p | 打印模式空间中的文本:打印当前模式空间中的内容。默认情况下,sed 会自动打印每一行,但使用 -n 选项时,只有被 p 命令标记的行才会被打印。 |
q | 退出 sed :退出 sed 程序。通常用于在处理完特定行后立即退出。 |
示例文本:
1. This is the first line.
2. This line contains the word "delete".
3. This is the third line.
4. This line should be removed.
# 5. This is the last line.
p(打印)
p
命令用于搜索符合符号条件的行,并输出该行的内容,其基本格式为:
[address]p
常见的用法是打印包含匹配文本模式的行,通常与 -n
选项配合使用,这样可以禁止输出其他行,仅打印包含匹配文本模式的行。如果不使用 -n
选项,sed
不仅会打印匹配 p
命令的每一行,还会打印文件的所有内容,因为 sed
本身在处理完每一行后会自动打印模式空间的内容。
打印文件中的所有行
shell[root@localhost ~]# sed -n 'p' example.txt 1. This is the first line. 2. This line contains the word "delete". 3. This is the third line. 4. This line should be removed. # 5. This is the last line.
打印文件中的第一行
shell[root@localhost ~]# sed -n '1p' example.txt 1. This is the first line.
打印文件中的第一行到第五行
shell[root@localhost ~]# sed -n '1,5p' example.txt 1. This is the first line. 2. This line contains the word "delete". 3. This is the third line.
打印文件中的第一行和第五行
shell[root@localhost ~]# sed -n '1p;5p' example.txt 1. This is the first line.
打印文件中除了第一行的内容
!
表示取反,使用1!p
可以实现此功能:shell[root@localhost ~]# sed -n '1!p' example.txt 2. This line contains the word "delete". 3. This is the third line. 4. This line should be removed. # 5. This is the last line.
使用扩展的正则表达式
当需要使用扩展的正则表达式时,需要加上
-r
选项:shell[root@localhost ~]# sed -nr '/1|2|3/p' example.txt 1. This is the first line. 2. This line contains the word "delete". 3. This is the third line.
例如,
$
表示最后一行,=
表示行号,打印文件中最后一行的行号:shell[root@localhost ~]# sed -nr '$=' example.txt 7
使用正则打印文件中包含
third
的行:shell[root@localhost ~]# sed -nr '/third/p' example.txt 3. This is the third line.
d(删除)
如果需要删除文本中的特定行,可以使用 d
脚本命令,它会删除指定行中的所有内容,基本格式为:
[address]d
当和指定地址一起使用时,删除命令能发挥出强大的功用,可以从数据流中删除特定的文本行。但使用该命令时要特别小心,如果忘记指定具体行,文件中的所有内容都会被删除。
删除特定行
删除文件中的第 3 行:
shell[root@localhost ~]# sed '3d' example.txt 1. This is the first line. 3. This is the third line. 4. This line should be removed. # 5. This is the last line.
删除多个特定行
删除文件中的第 2 行和第 3 行:
shell[root@localhost ~]# sed '2d;3d' example.txt 1. This is the first line. 3. This is the third line. 4. This line should be removed. # 5. This is the last line.
删除匹配模式的行
删除包含单词
delete
的行:shell[root@localhost ~]# sed '/delete/d' example.txt 1. This is the first line. 3. This is the third line. 4. This line should be removed. # 5. This is the last line.
删除多个匹配模式的行
删除包含
delete
或removed
的行:shell[root@localhost ~]# sed '/delete/d;/removed/d' example.txt 1. This is the first line. 2. This is the third line. # 5. This is the last line.
删除空行
删除文件中的所有空行:
shell[root@localhost ~]# sed '/^$/d' example.txt 1. This is the first line. 2. This line contains the word "delete". 3. This is the third line. 4. This line should be removed. # 5. This is the last line.
sed '/^$/d'
命令通过正则表达式/^$/
匹配空行。^
表示行的开头;$
表示行的结尾。如果一个行只包含行的开头和结尾,而中间没有任何字符,那么这个行就是空行。因此,/^$/
可以精确地匹配那些没有任何字符的空行。删除以特定字符开头的行
删除以
#
开头的注释行:shell[root@localhost ~]# sed '/^#/d' example.txt 1. This is the first line. 2. This line contains the word "delete". 3. This is the third line. 4. This line should be removed.
sed
的删除命令 d
非常灵活,可以结合行号、正则表达式等条件来精确地删除指定的行。需要强调的是,在默认情况下 sed
并不会修改原始文件,这里被删除的行只是从 sed
的输出中消失了,原始文件并未做任何改变。如果想要修改原始文件,则需要加上 -i
选项。
s(替换)
sed
的 replace
命令(s)是其最强大且最常用的命令之一,用于替换文本中的某些内容。它支持正则表达式,可以实现非常灵活的文本替换操作。基本格式为:
[address]command/pattern/replacement/flags
address
:可选的地址范围,用于指定命令作用的行。可以是行号、正则表达式或两者的组合。pattern
:要匹配的内容,可以是普通字符串或正则表达式。replacement
:替换后的内容,可以包含普通字符或特殊字符(如\1
、\2
等,用于引用匹配的子表达式)。flags
:可选的标志,用于修改替换操作的行为。
sed
的 flags
介绍:
标志 | 描述 |
---|---|
n | 1~512 之间的数字,表示指定要替换的字符串出现第几次时才进行替换,例如,一行中有 3 个 A ,但用户只想替换第二个 A ,这是就用到这个标记; |
g | 对数据中所有匹配到的内容进行替换,如果没有 g ,则只会在第一次匹配成功时做替换操作。例如,一行数据中有 3 个 A ,则只会替换第一个 A ; |
p | 会打印与替换命令中指定的模式匹配的行。此标记通常与 -n 选项一起使用。 |
w | 将缓冲区中的内容写到指定的文件中。 |
y | 表示把一个字符翻译为另外的字符(但是不用于正则表达式) |
\n | 匹配第 n 个子串,该子串之前在 pattern 中用 \(\) 指定。 |
& | 用正则表达式匹配的内容进行替换。 |
需要注意的是,flags
不仅仅针对替换命令,它是一些可选标志,可以用于多种 sed
命令,当然不同的命令支持的 flags
也不尽相同。
替换功能实例:
This is a test of the trial script.
This is the second test of the trial script.
This is a different line.
指定替换次数
可以指定
sed
用新文本替换第几处模式匹配的地方:shell[root@localhost ~]# sed 's/test/trial/2' flags.txt This is a test of the trial script. This is the second test of the trial script. This is a different line.
可以看到,使用数字
2
作为标志的结果就是,sed
编辑器只替换每行中第 2 次出现的匹配模式。全局替换
如果要用新文件替换所有匹配的字符串,可以使用
g
标记:shell[root@localhost ~]# sed 's/test/trial/g' flags.txt This is a trial of the trial script. This is the second trial of the trial script. This is a different line.
仅输出被替换的行
-n
选项会禁止sed
输出,但p
标记会输出修改过的行,将二者配合使用的效果就是只输出被替换命令修改过的行:shell[root@localhost ~]# sed -n 's/test/trial/p' flags.txt This is a trial of the trial script. This is the second trial of the trial script.
保存匹配结果到指定文件
w
标记会将匹配后的结果保存到指定文件中:shell[root@localhost ~]# sed 's/test/trial/w flags1.txt' flags.txt This is a trial line. This is a different line.
shell[root@localhost ~]#cat test.txt This is a trial line.
处理文件路径替换
在使用
s
脚本命令时,替换类似文件路径的字符串会比较麻烦,需要将路径中的正斜线进行转义:shell[root@localhost ~]# sed 's/\/bin\/bash/\/sbin\/sh/' /etc/passwd
使用转义符可以成功,但非常不方便。最佳方案是使用替换符号,可以用数字上的所有符号代替:
shell[root@localhost ~]# sed 's!/bin/bash!/sbin/sh!' /etc/passwd [root@localhost ~]# sed 's@/bin/bash@/sbin/sh@' /etc/passwd
参考案例:
2017 2011 2018
2017 2017 2024
2017 2017 2017
替换每行的第一个匹配项
将文件中的所有行的第一个
2017
替换成abcd
,由于没有指定地址,就是所有行都进行替换,但是只会替换行中的第一个:shell[root@localhost ~]# sed 's/2017/abcd/' sed.txt abcd 2011 2018 abcd 2017 2024 abcd 2017 2017
替换指定行的第一个匹配项
将文件中的第二行的第一个
2017
替换成hello
:shell[root@localhost ~]# sed '2s/2017/hello/' sed.txt 2017 2011 2018 hello 2017 2024 2017 2017 2017
替换指定行的指定次匹配项
将文件中的第二行的第二个
2017
替换成hello
:shell[root@localhost ~]# sed '2s/2017/hello/2' sed.txt 2017 2011 2018 2017 hello 2024 2017 2017 2017
替换符合条件行的指定次匹配项
匹配以
2017
结尾的行,将第三个2017
替换为abcd
:shell[root@localhost ~]# sed '/2017$/s/2017/abcd/3' sed.txt 2017 2011 2018 2017 2017 2024 2017 2017 abcd
替换符合条件行的所有匹配项
匹配以
2017
结尾的行,将全部的2017
替换为abcd
:shell[root@localhost ~]# sed '/2017$/s/2017/abcd/g' sed.txt 2017 2011 2018 2017 2017 2024 abcd abcd abcd
a 和 i(添加)
sed
的添加功能(a
和 i
命令)用于在指定行的上方或下方插入文本。
- 在指定行下方插入文本(
a
命令):
[address]a\text
- 在指定行上方插入文本(
i
命令):
[address]i\text
注意,text 前面的反斜杠 \
是必需的,用于指示 sed
在下一行继续读取命令。如果需要插入多行文本,可以使用多个反斜杠 \
来分隔每行。
示例文本:
1. This is the first line.
2. This line contains the word "delete".
3. This is the third line.
4. This line should be removed.
# 5. This is the last line.
在指定行下方插入文本
在第 2 行下方插入
Hello, world!
:shell[root@localhost ~]# sed '2a\Hello, world!' example.txt 1. This is the first line. Hello, world! 2. This line contains the word "delete". 3. This is the third line. 4. This line should be removed. # 5. This is the last line.
在指定行上方插入文本
在第 3 行上方插入
Hello, world!
:shell[root@localhost ~]# sed '3i\Hello, world!' example.txt 1. This is the first line. Hello, world! 2. This line contains the word "delete". 3. This is the third line. 4. This line should be removed. # 5. This is the last line.
在匹配模式的行下方插入文本
在包含
delete
的行下方插入This line will be marked.
:shell[root@localhost ~]# sed '/delete/a\This line will be marked.' example.txt 1. This is the first line. 2. This line contains the word "delete". This line will be marked. 3. This is the third line. 4. This line should be removed. # 5. This is the last line.
在文件末尾插入文本
在文件末尾插入
This is the new last line.
:shell[root@localhost ~]# sed '$a\This is the new last line.' example.txt 1. This is the first line. 2. This line contains the word "delete". 3. This is the third line. 4. This line should be removed. # 5. This is the last line. This is the new last line.
c(整行替换)
sed
的 c
命令用于将指定行的整个内容替换为新的文本。这个命令会完全删除指定行的内容,并用新的文本替换。基本格式为:
[address]c\text
示例文本:
1. This is the first line.
2. This line contains the word "delete".
3. This is the third line.
4. This line should be removed.
# 5. This is the last line.
替换特定行
将第 3 行替换为
New content here.
:shell[root@localhost ~]# sed '3c\New content here.' example.txt 1. This is the first line. New content here. 3. This is the third line. 4. This line should be removed. # 5. This is the last line.
替换匹配模式的行
将包含
third
的行替换为New content here.
:shell[root@localhost ~]# sed '/third/c\New content here.' example.txt 1. This is the first line. 2. This line contains the word "delete". New content here. 4. This line should be removed. # 5. This is the last line.
替换最后一行
将最后一行替换为
This is the new last line.
:shell[root@localhost ~]# sed '$c\This is the new last line.' example.txt 1. This is the first line. 2. This line contains the word "delete". 3. This is the third line. 4. This line should be removed. This is the new last line.
y(转换)
sed
的 y
命令用于对文本中的字符进行一对一的转换。它是一个非常强大的工具,可以快速地将文本中的某些字符替换为其他字符。基本格式为:
[address]y/inchars/outchars/
inchars
:要被替换的字符集合。outchars
:替换后的字符集合。
sed
的 y
命令会对 inchars
和 outchars
中的字符进行一对一的映射。例如,inchars
中的第一个字符会被替换为 outchars
中的第一个字符,第二个字符会被替换为 outchars
中的第二个字符,依此类推。如果 inchars
和 outchars
的长度不同,sed
会产生一条错误消息。
注意,转换命令是一个全局命令,也就是说,它会文本行中找到的所有指定字符自动进行转换,而不会考虑它们出现的位置。
示例文本:
This is line number 1 OK?.
This is line number 2.
This is line number 3.
替换特定字符
将所有
1
替换为7
,2
替换为8
,3
替换为9
:shell[root@localhost ~]# sed 'y/123/789/' example2.txt This is line number 7 OK?. This is line number 8. This is line number 9.
替换指定行中的字符
只对第 2 行进行字符替换:
shell[root@localhost ~]# sed '2y/123/789/' example2.txt This is line number 1 OK?. This is line number 8. This is line number 3.
替换匹配模式的行中的字符
对包含
OK
的行进行字符替换:shell[root@localhost ~]# sed '/OK/y/123/789/' example2.txt This is line number 7 OK?. This is line number 2. This is line number 3.
w (写入文件)
sed 的 w 命令用于将模式空间中的内容写入到指定的文件中。基本格式为:
[address1[,address2]]w file
file
:目标文件路径,也就是内容要备份/拷贝到的目标文件地址。address1
和address2
:分别是起始地址和结束地址 ,可以是行号或模式字符串。file
可以使用相对路径或绝对路径,但不管是哪种,运行sed
命令的用户都必须有文件的写权限。
address1
和 address2
都是可选参数,可以都不填,这时候就是全文件拷本/备份了。如果存在一个,那么就是备份单行。
w
命令会将模式空间中的内容写入到指定的文件中。如果目标文件不存在,sed
会创建该文件。如果目标文件已经存在,sed
会覆盖原文件的内容,而不是追加。
示例文本:
1) 小明,23 岁,北京大学
2) 小红,22 岁,清华大学
3) 小李,25 岁,斯坦福大学
4) 小王,22 岁,清华大学
- 将整个文件的内容写入目标文件
将整个 example3.txt 文件的内容写入到 output.txt 中:
[root@localhost ~]# sed 'w output.txt' example3.txt
1) 小明,23 岁,北京大学
2) 小红,22 岁,清华大学
3) 小李,25 岁,斯坦福大学
4) 小王,22 岁,清华大学
sed
在处理文件时,默认会将处理后的每一行输出到标准输出(通常是屏幕)。即使使用了 w
命令将某些行写入到文件中,sed
仍然会将所有行输出到标准输出,除非明确禁止这种行为。只想将内容写入到文件中,而不希望看到标准输出,可以使用 -n
选项来禁止默认输出。
[root@localhost ~]# cat output.txt
1) 小明,23 岁,北京大学
2) 小红,22 岁,清华大学
3) 小李,25 岁,斯坦福大学
4) 小王,22 岁,清华大学
- 将第 3 行写入目标文件
将第 3 行的内容写入到 output.txt 中:
[root@localhost ~]# sed -n '3w output.txt' example3.txt
[root@localhost ~]# cat output.txt
3) 小李,25 岁,斯坦福大学
- 将匹配模式的行写入目标文件
将包含清华大学的行写入到 output.txt 中:
sed -n '/清华大学/w output.txt' example3.txt
[root@localhost ~]# cat output.txt
2) 小红,22 岁,清华大学
4) 小王,22 岁,清华大学
r(从文件中读取内容)
sed 的 r 命令用于从指定的文件中读取内容,并将其插入到模式空间中指定的位置。基本格式为:
[address]r file
r
命令会将指定文件的内容读取并插入到模式空间中指定行的下方。如果 address
省略,则默认在所有行之后插入文件内容;如果 address
指定为行号或正则表达式,则只在匹配的行之后插入文件内容。
示例文本:
1) 小明,23 岁,北京大学
2) 小红,22 岁,清华大学
3) 小李,25 岁,斯坦福大学
4) 小王,22 岁,清华大学
这是插入的内容
在指定行之后插入文件内容
在 example3.txt 的第 2 行之后插入 insert.txt 的内容:
shell[root@localhost ~]# sed '2r insert.txt' example3.txt 1) 小明,23 岁,北京大学 2) 小红,22 岁,清华大学 这是插入的内容 3) 小李,25 岁,斯坦福大学 4) 小王,22 岁,清华大学
shell[root@localhost ~]# cat example3.txt 1) 小明,23 岁,北京大学 2) 小红,22 岁,清华大学 3) 小李,25 岁,斯坦福大学 4) 小王,22 岁,清华大学
注意,
sed
在处理文件时,默认会将处理后的每一行输出到标准输出(通常是屏幕),但不会直接修改原始文件,除非明确指定使用-i
选项。因此,看到的输出是处理后的结果,但 example3.txt 文件本身并没有被修改。在匹配模式的行之后插入文件内容
在包含清华大学的行之后插入 insert.txt 的内容:
shell[root@localhost ~]# sed '/清华大学/r insert.txt' example3.txt 1) 小明,23 岁,北京大学 2) 小红,22 岁,清华大学 这是插入的内容 3) 小李,25 岁,斯坦福大学 4) 小王,22 岁,清华大学 这是插入的内容
在文件末尾插入文件内容
在 example3.txt 的末尾插入 insert.txt 的内容:
shell[root@localhost ~]# sed '$r insert.txt' example3.txt 1) 小明,23 岁,北京大学 2) 小红,22 岁,清华大学 3) 小李,25 岁,斯坦福大学 4) 小王,22 岁,清华大学 这是插入的内容
q(退出脚本)
sed
的 q
命令用于在处理完指定的行或模式后立即退出 sed
脚本,其基本格式为:
[address]q [exit code]
exit code
:可选的退出状态码,用于指定sed
程序退出时的状态码。
q
命令会在到达指定的行或匹配模式后立即退出 sed
脚本,不再处理后续的行。如果没有指定 address
,sed
会在处理完第一行后立即退出。如果指定了 exit code
,sed
会以该状态码退出。
这个命令在处理大文件时非常有用,因为它可以让快速地查看文件的前几行内容,而不需要等待整个文件被处理完毕。如果只想查看一个大文件的前 10 行内容,可以使用下面的命令:
[root@localhost ~]# sed '2q' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
在匹配模式的行之后退出
在匹配到北京大学的行之后退出 sed 脚本:
shell[root@localhost ~]# sed '/北京大学/q' example3.txt 1) 小明,23 岁,北京大学
指定退出状态码
在匹配到斯坦福大学的行之后退出 sed 脚本,并指定退出状态码为 100:
shell[root@localhost ~]# sed '/斯坦福大学/q 100' example3.txt 1) 小明,23 岁,北京大学 2) 小红,22 岁,清华大学 3) 小李,25 岁,斯坦福大学
可以使用
$?
来检查刚刚的退出码:shell[root@localhost ~]# echo $? 100
参考示例
修改 Yum 软件仓库的配置文件,将默认的镜像源地址从 http://dl.rockylinux.org/
替换为阿里云的镜像源地址 https://mirrors.aliyun.com/rockylinux
,从而加快软件包的下载速度。
sed -e 's|^mirrorlist=|#mirrorlist=|g' \
-e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \
-i.bak \
/etc/yum.repos.d/[Rr]ocky*.repo
-e
:允许在命令行中指定多个编辑命令。在此案例中,使用了两个-e
选项来执行两个不同的替换操作。's|^mirrorlist=|#mirrorlist=|g'
:这是第一个编辑命令,使用了s
(替换)命令。^
表示行首,mirrorlist=
是要被替换的字符串,#mirrorlist=
是替换后的内容。g
表示全局替换,即对每一行中所有匹配的内容进行替换。此命令的作用是将所有以mirrorlist=
开头的行替换为以#mirrorlist=
开头,从而注释掉这些行。's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g'
:这是第二个编辑命令,同样使用了s
命令。它将匹配到的#baseurl=
开头的行替换为新的baseurl=
内容,从而将默认的镜像源地址http://dl.rockylinux.org/
替换为https://mirrors.aliyun.com/rockylinux
。-i.bak
:表示直接在原始文件上进行编辑,并创建一个带有.bak
后缀的备份文件。如果命令执行过程中出现错误,可以通过备份文件恢复原始配置。/etc/yum.repos.d/[Rr]ocky*.repo
:这是要修改的文件路径。文件名使用了通配符[Rr]ocky*.repo
,表示匹配 /etc/yum.repos.d/ 目录下所有以rocky
或Rocky
开头、以.repo
结尾的文件。
注意,sed
命令中的 s
命令通常使用 /
字符作为分隔符,但实际上可以使用任何其他字符作为分隔符。在这种情况下,脚本使用 |
字符作为分隔符。这样做的原因是,替换的文本中包含 /
字符,那么使用 /
作为分隔符会使脚本变得混乱。
脚本寻址方式
sed 脚本的寻址方式用于指定命令作用的具体行或行范围。默认情况下,sed 命令会作用于文本的所有行。如果只想将命令作用于特定行或某些行,则必须明确指定地址范围(address)。sed 支持多种寻址方式,包括数字、正则表达式和特殊字符。
以数字形式指定行区间
当使用数字方式的行寻址时,可以用行在文本流中的行位置来引用。sed
会将文本流中的第一行编号为 1,然后继续按顺序为接下来的行分配行号。
在脚本命令中,指定的地址可以是单个行号,或是用起始行号、逗号以及结尾行号指定的一定区间范围内的行。这里举一个 sed
命令作用到指定行号的例子:
[root@localhost ~]# sed '2s/小红/小绿/' example3.txt
1) 小明,23 岁,北京大学
2) 小绿,22 岁,清华大学
3) 小李,25 岁,斯坦福大学
4) 小王,22 岁,清华大学
可以看到,sed
只修改地址指定的第二行的文本。下面的例子中使用了行地址区间:
[root@localhost ~]# sed '2,3s/小/大/' example3.txt
1) 小明,23 岁,北京大学
2) 大红,22 岁,清华大学
3) 大李,25 岁,斯坦福大学
4) 小王,22 岁,清华大学
在此基础上,如果想将命令作用到文本中从某行开始的所有行,可以用特殊符号 $
:
[root@localhost ~]# sed '2,$s/小/大/' example3.txt
1) 小明,23 岁,北京大学
2) 大红,22 岁,清华大学
3) 大李,25 岁,斯坦福大学
4) 大王,22 岁,清华大学
用文本模式指定行区间
sed
允许指定文本模式来过滤出命令要作用的行,格式如下:
/pattern/command
注意,必须用正斜线将要指定的 pattern
封起来,sed
会将该命令作用到包含指定文本模式的行上。这里举一个 sed
命令作用到文本的例子:
[root@localhost ~]# sed '/小明/s/北京大学/中科院/' example3.txt
1) 小明,23 岁,中科院
2) 小红,22 岁,清华大学
3) 小李,25 岁,斯坦福大学
4) 小王,22 岁,清华大学
虽然使用固定文本模式能帮你过滤出特定的值,就跟上面的例子一样,但其作用难免有限,因此,sed
允许在文本模式使用正则表达式指明作用的具体行:
[root@localhost ~]# sed '/22 岁/s/小/大/' example3.txt
1) 小明,23 岁,北京大学
2) 大红,22 岁,清华大学
3) 小李,25 岁,斯坦福大学
4) 大王,22 岁,清华大学
标签
在 sed
中,标签(label)是一种用于控制命令执行流程的机制,它允许在处理文本时根据条件跳转到指定的位置。
标签由一个冒号 :
后面紧跟一个字母数字组成的名称构成,例如 :label1
、:loop
等。标签通常放在 sed
脚本中的某一行开头,用于标识一个特定的位置。例如:
plaintext:label1
s/old/new/
这里定义了一个名为 label1
的标签,它后面跟着一条替换命令 s/old/new/
。
在 sed
中,跳转命令是与标签配合使用的功能,用于控制命令执行的流程。这些跳转命令允许 sed
在处理文本时根据条件跳转到指定的标签位置,从而实现循环、条件分支等复杂的逻辑。
sed
提供了三种主要的跳转命令:
b
(branch):无条件跳转到指定的标签。t
(test):如果上一次的替换操作(s 命令)成功,则跳转到指定的标签。T
(Test):如果上一次的替换操作失败,则跳转到指定的标签。
如果跳转命令中省略了标签名称,则默认跳转到脚本的末尾。
b
b
命令主要用于跳过某些操作、实现循环或提前终止处理。
b [标签名]
测试文本:
apple pie
ignore this line
apple juice
ignore another line
banana split
跳过包含 ignore
的行,处理其他行:
sed -n '
/ignore/ b end
s/apple/orange/
p
:end
' sed_b.txt
/ignore/ b end
:这是一个条件判断和跳转命令。它的作用是检查当前行是否包含ignore
这个字符串,如果包含,则使用b
命令无条件跳转到标签end
处,也就是跳过后面的命令,直接进入下一次循环,处理下一行。s/apple/orange/
:如果当前行不包含ignore
,则执行这个替换命令,将行中的apple
替换为orange
。
orange pie
orange juice
banana split
t
t 命令主要实现条件分支逻辑,例如循环替换或根据替换结果执行不同操作。
t [标签名]
循环替换所有逗号为空格:
shellecho "a,b,c" | sed ' :loop # 定义一个名为 "loop" 的标签 s/,/ / # 尝试将第一个逗号替换为空格 t loop # 如果替换成功,跳转回 "loop" 标签,继续处理 '
首先定义一个名为
loop
的标签。标签的作用是提供一个跳转目标,用于循环或条件跳转。在这里,loop
是循环的起点。s/,/ /
这是一个替换命令,尝试将模式空间中的第一个逗号(,
)替换为空格( )。注意:sed
的替换命令默认只替换每行中的第一个匹配项。如果需要替换所有匹配项,需要加上g
标志(如s/,/ /g
),但在这个例子中,通过循环来实现多次替换。t
是条件跳转命令,表示「如果上一次的替换操作成功,则跳转到指定的标签」。在这里,如果s/,/ /
成功替换了逗号,sed
会跳转回loop
标签,继续处理下一次替换。如果替换失败(即模式空间中已经没有逗号),则继续执行后续命令(在这个例子中,后续没有命令,因此直接输出结果)。texta b c
循环处理(删除行首所有连续数字)
shellecho "123abc" | sed ' :start # 定义一个名为 "start" 的标签 s/^[0-9]// # 删除模式空间中的第一个数字(如果它在行首) t start # 如果替换成功,跳转回 "start" 标签继续处理 '
textabc
条件分支(替换成功时打印新内容,否则打印原内容)
shellsed -n ' s/apple/orange/ # 尝试将 "apple" 替换为 "orange" t success # 如果替换成功,跳转到标签 `success` s/.*/[WARNING] No apple found in this line: &/ # 替换失败,生成警告信息 p # 打印警告信息 b end # 跳转到标签 `end`,结束当前行处理 :success # 替换成功时的标签 p # 打印替换后的内容 :end # 结束标签 ' sed_b.txt
textorange pie [WARNING] No apple found in this line: ignore this line orange juice [WARNING] No apple found in this line: ignore another line [WARNING] No apple found in this line: banana split
T
T
命令处理未匹配到模式的情况,实现「失败分支」逻辑。
T [标签名]
与 t
的对比:
命令 | 触发条件 | 用途场景 |
---|---|---|
t | 最近的 s 替换成功时跳转 | 替换成功后的处理(如循环替换、成功分支) |
T | 最近的 s 替换失败时跳转 | 替换失败后的处理(如回退、错误处理) |
条件分支:替换失败时执行特定操作
将行中的
apple
替换为orange
,若替换失败则打印警告:shellsed -n ' s/apple/orange/ # 尝试替换 T error # 如果失败,跳转到 `error` 标签 p # 替换成功时打印 b end # 跳过错误处理 :error s/.*/[WARNING] No apple found: &/ # 修改内容为警告信息 p :end ' sed_b.txt
shellorange pie [WARNING] No apple found: ignore this line orange juice [WARNING] No apple found: ignore another line [WARNING] No apple found: banana split
跳过未匹配的行
仅处理包含数字的行,跳过其他行。
shellsed -n ' s/[0-9]/&/ # 尝试匹配行中的第一个数字 T skip # 如果没有匹配到数字,跳转到标签 "skip" s/.*/Found: &/p # 匹配到数字后,将整行替换为 "Found: <原始行内容>" 并打印 :skip # 定义跳过逻辑的标签 ' sed_b.txt
多行命令
在深入学习 sed
命令的基础功能时,会发现一个明显的局限性:常规的 sed
命令通常仅针对单行数据进行操作。
常规的 sed
命令通常仅针对单行数据进行操作,这是因为:
- 逐行读取机制:
sed
在读取输入数据时,会以换行符为分隔符,将文本逐行加载到模式空间(Pattern Space)中。每处理完一行,模式空间就会被清空,准备加载下一行。 - 模式空间的限制:模式空间默认只包含当前行的内容,无法直接感知当前行与其他行的上下文关系。因此,
sed
默认只能对单行数据进行操作。 - 输出即刻性:处理完当前行后,
sed
会立即将模式空间中的内容输出,而不是保留多行数据以供后续操作。
这种单行操作的局限性在实际文本处理场景中常常显得不足。例如,在处理跨多行的代码块、日志文件中的多行记录、或者需要匹配特定模式范围的文本时,单行操作无法满足需求。因此,sed
提供了一些特殊的机制和命令,用于实现多行操作。
为了突破单行操作的限制,sed
通过模式空间和保持空间的配合,以及一些特殊的命令,实现了对多行数据的操作:
- 模式空间(Pattern Space):这是
sed
的主要工作区域,每行输入文本会被加载到模式空间中,然后执行所有命令。默认情况下,模式空间只包含当前行。 - 保持空间(Hold Space):这是一个额外的存储区域,用于暂存数据。它与模式空间相互独立,可以通过特定命令在两者之间传递数据。
通过模式空间和保持空间的配合,sed
可以实现多行数据的累积和操作。
同时 sed
提供了三个专门用于处理多行文本的特殊命令:
- Next 命令(N):将数据流中的下一行加进来创建一个多行组来处理。
- Delete(D):删除多行组中的一行。
- Print(P):打印多行组中的一行。
N(多行操作)
N
命令的作用是将数据流中的下一行添加到当前行,从而创建一个多行组进行处理。在默认情况下,sed
一次只处理一行数据,使用 N
命令可以打破这种限制,让 sed
能够同时处理多行内容。例如,我们需要查找跨越两行的特定字符串时,就可以使用 N
命令将两行合并,以便进行匹配操作。
示例文本:
This is the header line.
This is the first data line. This is the second data line.
This is the last line.
function name1() {
param1,
param2,
param3
}
例如,合并包含特定单词的两行为一行:
[root@localhost ~]# sed '/first/{ N ; s/\n/ / }' line_sed1.txt
This is the header line.
This is the first data line. This is the second data line.
This is the last line.
在这个例子中,sed
命令查找包含单词 first
的行。找到该行后,它会用 N
命令将下一行合并到当前行,然后用替换命令 s
将换行符 \n
替换为空格。结果是,文本文件中的两行在 sed
的输出中合并为了一行。这种操作在处理跨越多行的文本时非常有用。
还可以使用 sed
的 N
命令和循环结构,将所有行合并为一行,并删除多余的换行符:
[root@localhost ~]# sed ':a;N;$!ba;s/\n//g' line_sed2.txt
function name1() { param1, param2, param3}
在这个例子中,sed
使用 :a
标签和循环结构,将文件中的所有行逐步合并到模式空间中,并最终删除所有换行符,将整个文件的内容合并为一行。
D(多行删除)
sed
不仅提供了单行删除命令(d
),也提供了多行删除命令 D
,其作用是只删除缓冲区中的第一行,也就是说,D
命令将缓冲区中第一个换行符(包括换行符)之前的内容删除掉。
示例文本:
hello
world.
hello world.
his is the header line.
This is a data line.
This is the last line.
可以查看下面例子:
[root@localhost ~]# sed 'N ; /hello\nworld/D' line_sed3.txt
world.
hello world.
N
是把下一行加到当前行后面,中间用一个换行符 \n
分隔,经过 N
后变成 hello\nworld.
,然后这里的 /hello\nworld/
是匹配包含 hello\nworld
的内容。D
的作用是删除模式空间中直到第一个换行符 \n
为止的内容。也就是说,如果匹配到 hello\nworld
,D
只会删除 hello
,而不会删除后面的 world
。
简单来说文本的第二行被 N
命令加到了缓冲区,因此 sed
命令第一次匹配就是成功,而 D
命令会将缓冲区中第一个换行符之前(也就是第一行)的数据删除,所以,得到了如上所示的结果。
如果目标是删除包含 hello
和紧接着的 world
的行,可以使用以下命令:
[root@localhost ~]# sed '/hello/{N;/hello\nworld/d}' line_sed3.txt
hello world.
这里首先使用 /hello/
找到包含 hello
的行。然后 N;
把下一行加进来。然后现在的内容是 hello\nworld
,就使用 d
删除整行,而不是只删除到换行符为止。
下面的例子中,它会删除数据流中出现在第一行前的空白行:
[root@localhost ~]# sed '/^$/{N;/header/D}' line_sed4.txt
his is the header line.
This is a data line.
This is the last line.
sed
会查找空白行,然后用 N
命令来将下一文本行添加到缓冲区。此时如果缓冲区的内容中含有单词 header
,则 D
命令会删除缓冲区中的第一行。
P(多行打印)
在 sed
命令中,P
(大写)命令和单行打印命令 p
(小写)的功能有所不同,就如同 d
和 D
之间存在区别一样。对于包含多行数据的缓冲区,大写 P 命令仅打印缓冲区中的第一行,即首个换行符之前的全部内容。
示例文本:
111
222
333
444
555
666
分别使用 p
(小写)命令和 P
(大写)命令处理 line_sed5.txt 文件内容后,输出信息对比如下:
[root@localhost ~]# sed -n '/.*/N;p' line_sed5.txt
111
222
333
444
555
666
由于每一行都与 /.*/
模式匹配,所以针对每一行都会执行 N;p
命令。也就是说,对于每一行,都会把下一行添加到模式空间,接着打印模式空间的内容。
[root@localhost ~]# sed -n '/.*/N;P' line_sed5.txt
111
333
555
N
命令会将下一行添加到模式空间,而 P
命令则会打印模式空间中直至第一个换行符的内容。所以,此命令会打印出 line_sed5.txt 文件中的所有奇数行。
具体来说:
- 处理第一行
111
时,N
命令会把下一行222
添加到模式空间,此时模式空间内容为111\n222
。随后执行P
命令,会打印模式空间中直到第一个换行符的内容,即111
。 - 处理第二行
222
时,因为上一步已将其添加到模式空间,所以这一步不会再次添加。因此,执行P
命令时不会输出任何内容。 - 处理第三行
333
时,同样会将下一行444
添加到模式空间,然后打印模式空间中直到第一个换行符的内容,即333
。 - 依此类推,最终打印结果为所有奇数行。
空间
在使用 sed 进行文本处理时,它提供了两个重要的空间来存储和操作文本,分别是模式空间(pattern space)和保留空间(hold space)。这两个空间在 sed 的文本处理流程中扮演着不同但又相互协作的角色。
模式空间
模式空间是 sed 处理每一行文本时的主要临时缓冲区。当 sed 开始处理文本文件时,它会逐行读取文件内容,并将每一行文本依次放入模式空间中进行处理。模式空间就像是一条流水线,文本行在其中接受各种 sed 命令的操作,如插入、删除、替换和转换等。
在默认情况下,如果没有使用 -n 选项,模式空间中的内容在处理完成后会主动打印到标准输出,并且模式空间会自动清空,以便处理下一行文本。
模式空间特点:
- 模式空间的内容会在每次处理完后自动清空,并加载下一行。
- 默认情况下,模式空间中的内容会被打印到标准输出。
- 模式空间可以被修改、替换或删除,例如通过 s(替换)、d(删除)等命令。
模式空间是 sed 的主要工作区域,用于对当前行进行编辑和处理。
保留空间
保留空间是 sed 提供的一个辅助临时缓冲区,类似于一个仓库。它用于存放稍后可能需要使用的文本,在模式空间对数据进行处理时,可以把部分或全部数据临时存储到保留空间中,以备后续操作使用。
与模式空间不同的是,保留空间的内容不会主动清空,也不会主动打印到标准输出,需要通过特定的 sed
命令来进行操作。需要注意的是,sed
命令通常是对模式空间进行操作,不能直接寻址保留空间,但可以通过上述的复制和交换命令,在模式空间和保留空间之间进行数据的交互,从而实现更复杂的文本处理需求。
保留空间特点:
- 保留空间的内容不会自动清空,也不会自动打印到标准输出。
- 它是一个独立的缓冲区,可以存储模式空间的内容,也可以将保留空间的内容复制回模式空间。
- 保留空间通常用于多行操作或需要暂存数据的场景。
保留空间相当于一个「仓库」,用于临时存储模式空间中的内容,以便在后续的处理中使用。
空间的交互
sed
提供了一组命令来在模式空间和保留空间之间移动文本。这些命令包括:
空间相关 | 描述 |
---|---|
h | 将模式空间的内容复制到保持空间。它会覆盖保持空间中的任何现有文本。 |
H | 将模式空间的内容追加到保持空间。它会在保持空间中的现有文本后面添加一个换行符,然后追加模式空间的内容。 |
g | 将保持空间的内容复制到模式空间。它会覆盖模式空间中的任何现有文本。 |
G | 将保持空间的内容追加到模式空间。它会在模式空间中的现有文本后面添加一个换行符,然后追加保持空间的内容。 |
x | 将模式空间中的内容复制到保留空间,同时将保留空间中的内容复制到模式空间。 |
通常,在使用 h
或 H
命令将字符串移动到保持空间后,最终还要用 g
、G
或 x
命令将保存的字符串移回模式空间。保持空间最直接的作用是,一旦将模式空间中所有的文件复制到保持空间中,就可以清空模式空间来加载其他要处理的文本内容。
由于有两个缓冲区域,下面的例子中演示了如何用 h
和 g
命令来将数据在 sed
缓冲区之间移动:
示例文本:
春有百花秋有月,
夏有凉风冬有雪。
若无闲事挂心头,
便是人间好时节。
[root@localhost ~]# sed -n '/凉风/ {h ; p ; n ; p ; g ; p }' line_sed6.txt
夏有凉风冬有雪。
若无闲事挂心头,
夏有凉风冬有雪。
对于 line_sed6.txt 文件中的每一行,都会检查是否匹配 /凉风/
。如果匹配,则执行大括号内的命令。
在例子中,只有第二行 夏有凉风冬有雪。
匹配该模式。因此,对于这一行,会执行以下命令:
h
:将模式空间的内容(即夏有凉风冬有雪。
)复制到保留空间。p
:打印模式空间的内容(即夏有凉风冬有雪。
)。n
:读取下一行(即若无闲事挂心头,
)并将其添加到模式空间。p
:打印模式空间的内容(即若无闲事挂心头,
)。g
:将保留空间的内容(即夏有凉风冬有雪。
)复制到模式空间。p
:打印模式空间的内容(即夏有凉风冬有雪。
)。