sed
sed
(Stream Editor)是一个流编辑器,它以逐行方式处理输入流(通常是文本文件),并根据指定的编辑命令进行相应的操作。
sed 的工作原理
- 逐行处理输入流:
sed
逐行读取输入流,并对每一行应用相应的编辑命令。输入流可以是文件、管道输出等。 - 模式匹配:
sed
使用模式来匹配文本中的特定部分。用户可以使用正则表达式或简单的字符串来定义匹配模式。 - 编辑命令:
sed
使用编辑命令来对匹配到的文本进行操作。编辑命令可以是替换命令、删除命令、插入命令等,以及一些控制流程的命令。 - 应用编辑命令: 一旦匹配到了指定的文本,
sed
就会根据相应的编辑命令执行相应的操作。这些操作可以是替换匹配文本、删除匹配行、插入新文本等。 - 输出结果:
sed
在处理完所有输入流后,将结果输出到标准输出(通常是终端),或者通过-i
参数直接在原文件上进行修改。
sed空间
在 sed
中,有两个特殊的空间:模式空间(pattern space)和保留空间(hold space)。这些空间允许在处理文本时存储和操作数据。
模式空间(pattern space): 模式空间是
sed
中用于存储当前处理的行的缓冲区。当sed
读取一行文本时,文本会被存储在模式空间中,sed
在模式空间中对其进行匹配和操作。模式空间中的内容可以被修改、替换或者通过命令输出到标准输出。默认情况下,sed
在处理完每一行后会自动清空模式空间,然后读取下一行。保留空间(hold space): 保留空间是另一个可用于存储数据的空间,与模式空间相互独立。可以使用保留空间来存储临时数据或在处理文本时进行比较。与模式空间不同,保留空间的内容不会随着处理的文本行而变化。
可以将数据从模式空间移动到保留空间,反之亦然。这使得 sed
能够在文本处理过程中灵活地使用和操作数据。
以下是一些 sed
命令,用于操作模式空间和保留空间中的数据:
h
:将模式空间中的内容复制到保留空间。H
:将模式空间中的内容追加到保留空间的末尾。g
:将保留空间中的内容复制到模式空间。G
:将保留空间中的内容追加到模式空间的末尾。x
:交换模式空间和保留空间中的内容。
除了模式空间(Pattern Space)和保留空间(Hold Space)外,还有以下几个空间或概念:
输入缓冲区(Input Buffer):这是
sed
从输入文件或标准输入读取当前行的地方。在读取一行后,sed
会将其放入模式空间中进行处理。输出缓冲区(Output Buffer):在默认情况下,
sed
会将处理后的模式空间内容立即输出。但是在某些情况下(如使用-n
选项时),输出会被暂存,直到明确调用p
或其他输出指令,或者处理结束时才会输出。命令行缓冲区(Command Line Buffer):
sed
脚本中的命令会被暂存到这个缓冲区中,随后按顺序应用于模式空间的内容。每一行在处理完毕后,sed
会继续读取下一行并重复这个过程。地址范围和上下文范围(Address and Context Range Buffers):当指定一个地址范围或上下文范围(如
sed '/start/,/end/'
)时,sed
会记住当前行是否在该范围内,以决定是否应用接下来的命令。
sed命令格式
sed [选项] ‘编辑命令’ 文件名
常用的选项包括:
-n
:关闭自动打印模式,只有经过编辑命令处理后的行才会输出。-e
:指定一个或多个编辑命令。-f
:从指定文件中读取编辑命令。
编辑命令是对文本进行操作的指令,可以是替换、删除、插入、打印等操作,常见的编辑命令包括:
s/old/new/g
:替换行中的old
字符串为new
。/pattern/d
:删除匹配到的行。/pattern/i\text
:在匹配到的行之前插入文本。/pattern/a\text
:在匹配到的行之后追加文本。/pattern/p
:打印匹配到的行。
sed指令
替换 s
:
s/old/new/g
:将行中所有的 old
替换为 new
。其中 g
表示全局替换,如果不加 g
,则只替换每行的第一个匹配。
除了g标志,还可以是具体数字:s/old/new/2,表示替换第2个。
p标志打印替换的行:s/old/new/p。
w标志可以将更改的行保存的文件中:s/old/new/w file.txt。
i或I标志表示不区分大小写:s/old/new/i
例如:sed 's/foo/bar/g' filename
:将文件中所有的 foo
替换为 bar
。
s命令除了可以使用/作为分隔符,还可以使用**| @ ! ^**作为分隔符
字符替换标志:
\L: 将紧随其后的所有字符转换为小写,直到遇到 \E
或字符串结束。
\U: 将紧随其后的所有字符转换为大写,直到遇到 \E
(结束转换)或字符串结束。
\l: 将紧随其后的第一个字符转换为小写。
\u: 将紧随其后的第一个字符转换为大写。
\E:用于结束 \L
或 \U
的作用范围。
删除d
删除的这行不会被输出到标准输出,因数它被删了。
/pattern/d
:删除匹配到的行。- 例如:
sed '/pattern/d' filename
:删除所有包含pattern
的行。
插入i \
/pattern/i\text
:在匹配到的行之前插入指定文本。- 例如:
sed '/pattern/i\new_text' filename
:在包含pattern
的行之前插入new_text
。
追加a \
/pattern/a\text
:在匹配到的行之后追加指定文本。- 例如:
sed '/pattern/a\new_text' filename
:在包含pattern
的行之后追加new_text
。
打印p
/pattern/p
:打印匹配到的行。- 例如:
sed -n '/pattern/p' filename
:仅打印包含pattern
的行。
替换y
y/chars1/chars2/
:将文本中chars1
中的字符替换为chars2
中对应位置的字符。- 例如:
sed 'y/abc/123/' filename
:将文件中所有的a
替换为1
,b
替换为2
,c
替换为3
。
其他指令
行范围命令 (start,end):
start,end\<命令>
:对指定行范围内的所有行执行指定的命令。
例如:sed '2,4{s/foo/bar/g}' filename
:对第 2 行到第 4 行之间的所有行,将所有的 foo
替换为 bar
。
行范围(start,+num):
从start开始的,num行
行范围(start~num):
从starjt行开始,每隔num行。注意和**(start,~num)**的区别
/pattern/,/pattern/或者start,/pattern/ 也可以混合地址和模式**/pattern/,+num**
!命令
用于反转命令的作用范围,它让命令仅对不匹配的行生效。
seq 1 10 | sed -n '1,5p'
, 输出1-5行。
seq 1 10 | sed -n '1,5!p'
, 输出除1-5行之外的行。
行号 num
n
:对指定行号的行执行指定的命令。- 例如:
sed '2{s/foo/bar/g}' filename
:对第 2 行,将所有的foo
替换为bar
。
替换行命令(c)
与 s
命令不同,c
命令不是进行模式替换,而是用新文本完全替换匹配的整行内容。非常适合用于替换整行内容,而不是在行内做部分替换。
显示隐藏字符(l)
显示非打印字符为其控制符。
1 | sed -n 'l' wawa.txt |
退出当前执行流程(q)
注意:quit 命令不接受地址范围,它仅支持单个地址。默认情况下,SED 遵循读取、执行和重复工作流程;但是当遇到quit命令时,它只是停止当前的执行。
1 | [root@MiWiFi-RA80-srv test]# sed '3q' wawa.txt |
标签命令 (:)::lable可用来创建循环和控制流程
跳转命令 (b):b label 无条件跳转到指定标签
(t):
转换命令 (y):
执行命令 (e):在匹配的行上执行指定的shell命令。
1 | # 在2,3,4,5行后附加whoami的输出内容 |
打印行号命令 (=):
=
:打印当前行号。将行号及其内容写入标准输出流- 例如:
sed -n '=' filename
:打印文件中每行的行号。 sed -n '$ ='filename
打印文件最后一行行号,也就是文件总共多少行
&命令
SED 支持特殊字符 &。每当模式匹配成功时,此特殊字符就会存储匹配的模式。它经常与替换命令一起使用。
1 | [root@MiWiFi-RA80-srv test]# cat a |
命令 (N):
N
命令将下一行读取到模式空间中,并将它追加到当前模式空间的内容后面(用换行符分隔),使得模式空间包含多行文本。
执行N:
当前模式空间的内容不会被清除。
读取下一行并将其追加到现有的模式空间内容后面。
模式空间现在包含两行或更多行的内容,可以对其进行进一步的处理。
例如:
sed 'N;s/foo\nbar/barfoo/' filename
:将匹配到foo
和bar
位于不同行的两行合并为一行,并将其替换为barfoo
。
1 | [root@testserver ~]# echo -e "a\naaa\nb\nc\naaaaaaa\naaa\ne" |sed 'N;s/a\+\na\+/@/' |
默认情况下,SED 在单行上运行,但它也可以在多行上运行。多行命令用大写字母表示。例如,与 n 命令不同,N 命令不会清除并打印模式空间。相反,它会在当前模式空间的末尾添加换行符 (\n),并将输入文件中的下一行附加到当前模式空间,并通过执行其余的 SED 命令继续 SED 的标准流程。
n命令
n 命令打印模式缓冲区的内容,清除模式缓冲区,将下一行提取到模式缓冲区中,然后对其应用命令。
n
命令会跳过当前行的进一步处理,直接读取下一行并用它替换模式空间中的内容,然后开始处理新行。
执行n命令后:
- 当前模式空间的内容会被清除。
- 读取下一行并将其放入模式空间。
- 从读取的新行开始执行剩余的
sed
脚本命令。
1 | [root@MiWiFi-RA80-srv test]# cat a |
打印模式空间命令 (p):
/pattern/,+1p
:打印匹配到的行及其下一行。- 例如:
sed -n '/pattern/,+1p' filename
:打印包含pattern
的行及其下一行。
读写文本命令 (r
、w
):
r filename
:在模式空间中的行后面追加指定文件中的内容。w filename
:将模式空间中的内容写入到指定文件中。- 例如:
sed '/pattern/r file.txt' filename
:在匹配到pattern
的行后追加file.txt
文件中的内容。
打印模式空间第一行(P)
与 p 命令类似, P 命令来打印由 N 命令创建的多行模式空间的第一部分(直到嵌入换行符)。如果没有有N,它和p命令相同。
命令(D )
D
命令会删除模式空间中的第一行,并重新开始处理剩余的模式空间。如果剩余的模式空间不为空,D
命令会跳转到脚本的开头重新执行,直到模式空间为空为止。
这种行为允许 sed
脚本在处理多行文本时实现循环处理的效果,从而允许对整个文件进行逐行处理而不是一次性处理整个文件。
1 | sed '$!N; /^\(.*\)\n\1$/!P;D' filename |
检查版本(v)
SED 还提供了一个 v 命令来检查版本。如果提供的版本高于安装的 SED 版本,则命令执行失败。请注意,此选项是 GNU 特定的,可能不适用于 SED 的其他变体。
h命令
h 命令处理保持缓冲区。它将数据从模式缓冲区复制到保持缓冲区。保持缓冲区中的现有数据将被覆盖。请注意,h 命令不会移动数据,它只会复制数据。因此,复制的数据在模式缓冲器中保持原样。
1 | [~/test]: cat a |
H命令
SED 提供了 H 命令,该命令通过在末尾添加新行将内容附加到保持缓冲区。 h 和 H 命令之间的唯一区别是,前者覆盖保持缓冲区中的数据,而后者将数据追加到保持缓冲区。
1 | [~/test]: sed -n '/Bob/!h;/Bob/{H;x;p}' a |
g命令
将数据从保持缓冲区复制到模式缓冲区。复制时,模式空间中的现有数据会被覆盖。
1 | [~/test]: sed -n '/Bob/!h;/Bob/{p;g;p}' a |
G命令
将保持缓冲区的内容附加到模式缓冲区。 SED 提供 G 命令,通过在末尾添加新行将内容附加到模式缓冲区。
1 | [~/test]: cat a |
x命令
交换模式空间和保持空间的内容
实例
有一个employee.txt的员工信息表,内容如下:
1 | Employee ID, Name, Department, Salary |
1 | # 除第一行末尾添加$符号 |
1 | # 递归处理目录下的多个文件,可以使用find结合sed |
在 find
命令中,-exec
选项后面可以跟随一个命令来执行。{}
表示 find
命令找到的文件名列表。;
表示命令的结尾,每找到一个文件就执行一次命令。+
则表示将找到的文件名作为参数传递给一个单独的命令,而不是每个文件都执行一次命令。
使用 +
可以有效地减少 sed
命令的调用次数,提高效率,因为 sed
命令一次可以处理多个文件。相比之下,使用 ;
每次只能处理一个文件,可能会导致 sed
命令被调用多次,性能较低。
如果你使用 \
替代 +
,即 {} \;
,则相当于告诉 find
命令每次找到一个文件就执行一次 sed
命令。这种方式的效率较低,因为 sed
命令会被频繁地调用,不如使用 +
效率高。
1 | [root@testserver test]# cat a |
1 | # 删除空行 |