shell流编辑器-sed
1 Sed流编辑器介绍
sed(stream editor)是一个强大的文本处理工具,用于在流(如文件或输入)中进行文本替换、删除、添加和其他文本操作。sed 工作方式是逐行读取输入,对每一行应用指定的操作,然后输出结果。sed 特别适用于批处理编辑和文本处理任务。
-
读取输入: sed 从输入流(通常是一个文件或标准输入)中逐行读取数据。如果没有指定输入文件,sed 会从标准输入读取。
-
应用编辑命令: 对每一行,sed 按顺序应用提供的编辑命令。命令可以是替换、删除、插入等。每个命令作用于当前处理的行。
-
输出处理结果: 处理完每一行后,sed 将结果行输出到标准输出(默认行为)。如果使用了 -i 选项,结果会直接写回输入文件。
-
重复上述步骤: 继续读取下一行,重复步骤2和步骤3,直到处理完所有输入行。
2 Sed命令格式
sed [options] 'command' file
3 Sed常用选项
选项 | 说明 | 示例 | 示例说明 |
---|---|---|---|
-e | 允许多次编辑,执行多个 sed 命令 | sed -e ‘s/foo/bar/’ -e ‘s/baz/qux/’ file | 对文件 file 执行两个替换操作,首先将所有的 foo 替换为 bar,然后将所有的 baz 替换为 qux。 |
-f | 从指定的文件读取 sed 命令 | sed -f script.sed file script.sed | 文件中包含 sed 命令,这些命令将被应用到文件 file 上。 |
-i | 直接在文件中进行修改而不是输出到标准输出 | sed -i ‘s/foo/bar/g’ file | 直接在文件 file 中将所有的 foo 替换为 bar,无需将输出重定向到新文件。 |
-n | 取消 sed 的默认输出,默认情况下 sed 会自动打印每一行。使用 -n 选项后,sed 只会打印那些被明确指定的行。通常结合 p 命令(打印命令)使用,以选择性地输出特定行。 | sed -n ‘s/foo/bar/p’ file | 将文件 file 中的 foo 替换为 bar,并且只打印被替换的行,其他行不会被打印。 |
-r | 使用扩展正则表达式 | sed -r 's/(foo | bar)/baz/’ file |
-s | 对每个文件独立处理(用在多个输入文件时) | sed -s ‘s/foo/bar/’ file1 file2 | 这个命令会分别对 file1 和 file2 进行替换操作,将 foo 替换为 bar,每个文件的处理是独立的 |
-u | 禁用输入缓冲,用于实时处理 tail -f log.txt | sed -u ‘s/error/warning/’ | 实时监视 log.txt 文件的新增内容,并将每一行中的 error 替换为 warning。-u 选项禁用了输入缓冲,适用于实时处理。 |
4 Sed常用命令及操作
4.1 基本命令总结
命令 | 说明 | 示例 | 示例说明 |
---|---|---|---|
s | 替换 | sed ‘s/foo/bar/’ file | 将 文件file中的foo 替换为 bar |
p | 打印 | sed -n ‘/pattern/p’ file | 打印文件file中匹配 pattern 的行 |
d | 删除 | sed ‘/pattern/d’ file | 删除file文件中匹配 pattern 的行 |
a | 追加 | sed ‘/pattern/a\new line’ file | 在匹配 pattern 的行后追加新行 |
i | 插入 | sed ‘/pattern/i\new line’ file | 在匹配 pattern 的行前插入新行 |
c | 修改 | sed ‘/pattern/c\new line’ file | 将匹配 pattern 的行改为新行 |
q | 退出 | sed ‘5q’ file | 处理到第5行后退出 |
w | 写入文件 | sed -n ‘1w first.txt’ input.txt | 将input.txt中的第一行写入到first.txt |
r | 读取文件 | sed ‘3r insert.txt’ output.txt | 读取insert.txt 文件的内容并在 output.txt 的第三行之后插入 |
4.2 命令介绍
4.2.1 替换(s)
# 将文件中的每一行中首次出现的 "foo" 替换为 "bar"
sed 's/foo/bar/' file.txt
# 全局替换,将文件中所有"foo"的替换为 "bar"
sed 's/foo/bar/g' file.txt
# 只替换第二次出现的 "foo"为"bar"
sed 's/foo/bar/2' file.txt
# 只替换每行起始的 "foo"
sed 's/^foo/bar/' file.txt
# 直接编辑文件,将所有 "foo" 替换为 "bar"
sed -i 's/foo/bar/g' file.txt
4.2.2 使用行寻址对特定行进行编辑
- 使用数字进行行寻址
# 将第 2 行的中的"foo"替换为"bar"
sed '2s/foo/bar/' file.txt
#将第 2 到第 4 行的"foo"替换为"bar"
sed '2,4s/foo/bar/' file.txt
# 从第 3 行开始到文件结尾替换内容
sed '3,$s/foo/bar/' file.txt
2. 使用模式匹配进行行寻址
# 先找到包含正则pattern的行,然后将匹配行中的"foo"替换为"bar"
sed '/pattern/s/foo/bar/' file.txt
# 删除包含正则 pattern 的行
sed '/pattern/d' file.txt
#同时找到包含 banana 或 cherry 的行,并将banana 和 cherry替换为BANANA和CHERRY
sed '/banana/s/banana/BANANA/; /cherry/s/cherry/CHERRY/' example.txt
# 使用行范围结合模式匹配,在 banana 到 date 范围内的行进行替换
sed '/banana/,/date/s/a/A/g' example.txt
4.2.3 删除(d)
# 删除匹配特定模式的行,删除 /etc/passwd 文件中包含 root 的所有行
sed '/root/d' /etc/passwd
# 删除 /etc/passwd 文件中的第 2 行到最后一行。
sed '2,$d' /etc/passwd
# 删除 /etc/passwd 文件中的第 3 行。
sed '3d' /etc/passwd
# 删除 /etc/passwd 文件中的第 3到5行。
sed '3,5d' /etc/passwd
# 删除 /etc/passwd 文件中的最后一行。
sed '$d' /etc/passwd
# 删除包含 "foo" 的行,然后替换剩余内容中的 "bar" 为 "baz"
sed '/foo/d; s/bar/baz/g' file.txt
4.2.4 插入(i)和追加(a)
#在第2行之前插入文本
sed '2i\This is a new line' example.txt
# 在第2行之后追加文本
sed '2a\This is an appended line' example.txt
# 在匹配 banana 的行之前插入文本
sed '/banana/i\Before banana' example.txt
# 在匹配 cherry 的行之后追加文本
sed '/cherry/a\After cherry' example.txt
#在第3行之前插入多行文本
sed '3i\Line one\nLine two' example.txt
#在匹配 date 的行之后追加多行文本
sed '/date/a\Line one\nLine two' example.txt
# 在第2行之后追加文本并将结果保存到 newfile.txt
sed '2a\This is an appended line' example.txt > newfile.txt
4.2.5 修改( c)
# 将文件中的所有包含 "foo" 行替换为 "This line is replaced"
sed '/foo/c\This line is replaced' file.txt
# 将文件中的第2行至第4行替换为 "This is the new content"
sed '2,4c\This is the new content' file.txt
4.2.6 文件处理 (w)和(r)
# 只将匹配的行写入新文件output.txt中
sed -n '/pattern/w output.txt' file.txt
# 将文件/etc/passwd中的所有root替换为ROOT,并将替换的行写入change.txt 文件
sed -n 's/root/ROOT/g w change.txt' /etc/passwd
# 将input.txt中的第一行写入到first.txt
sed -n '1w first.txt' input.txt
# 在 output.txt 的第三行之后插入 insert.txt 文件的内容。
sed '3r insert.txt' output.txt
5、Sed模式空间和保持空间
5.1 基本介绍
5.1.1 什么是模式空间
在 sed 中,模式空间(pattern space)是一个用于存储当前正在处理的文本行的临时工作区域。在 sed 处理文本时,每一行都会被依次存储在模式空间中,供 sed 命令处理。
当 sed 处理输入文本时,它逐行读取文本并将每一行存储在模式空间中。在模式空间中,sed 可以执行各种操作,例如搜索、替换、删除、打印等。模式空间的内容可以通过 sed 命令进行修改,并且这些修改可以影响到后续的处理步骤。
在 sed 命令链中,通常会使用各种命令来处理模式空间中的文本,例如 s(替换)、d(删除)、p(打印)等。这些命令可以在模式空间中对当前行进行操作,并且可以根据需要将结果输出到标准输出或者保存到文件中。
总之,模式空间是 sed 中用于存储当前正在处理的文本行的临时工作区域,是 sed 进行文本处理的核心部分。
5.1.2 什么是保持空间
保持空间(hold space)是一个备用的工作区域,用于存储临时数据。它可以在 sed 命令的执行过程中保持不变,直到显式地更新或清空。保持空间通常用于存储需要在处理多行文本时使用的额外信息,比如前一行的内容等。
保持空间的主要作用是提供一个存储临时数据的地方,以便在处理文本的过程中进行一些复杂的操作。一些 sed 命令(如 h、H、g、G)可以用来在模式空间和保持空间之间复制、交换数据。
在 sed 中,模式空间和保持空间是两个不同的工作区域,它们的主要区别在于模式空间用于存储当前正在处理的行的内容,而保持空间用于存储临时数据或其他需要在处理多行文本时使用的信息。
保持空间的典型用法包括:
- 在处理多行文本时保存上一行的内容以供后续使用。
- 将当前行的内容与之前处理过的行进行比较或合并。
- 在某些复杂的操作中,通过保持空间来保存中间结果或状态信息。
5.2 处理命令
命令 | 说明 |
---|---|
h | 模式空间的内容复制到保持空间 |
H | 将模式空间的内容追加到保持空间中 |
g | 将保持空间的内容复制回模式空间中 |
G | 将保持空间的内容追加回模式空间中 |
d | 删除模式空间的内容,开始下一个循环 |
x | 交换保持空间和模式空间的内容 |
5.3 使用示例
5.3.1 示例1 替换并追加
现有文本文件 filename 包含多行文本。
假设 filename 文件包含以下内容:
apple
banana
charry
现在想要将每一行中的 a 替换为 x,然后将替换后的行追加到原始行后面,最终输出结果。
运行以下 sed 命令:
sed 'h; s/a/x/; G' filename
输出结果将会是:
apple
xpple
banana
bxnana
charry
chxrry
这个例子展示了 sed 命令如何在每一行中将 a 替换为 x,然后将原始行和替换后的行合并输出。
5.3.2 示例2 处理日志文件
假设有一个包含如下内容的日志文件 logfile.txt:
2024-06-01 12:34:56 - User logged in
2024-06-01 12:35:01 - Performing action A
2024-06-01 12:35:05 - Performing action B
2024-06-01 12:35:10 - User logged out
现在,想要查找每个用户会话的登录和注销时间,并计算其会话持续时间。这个任务涉及到跨越多行的文本模式匹配和处理。
示例 sed 命令链:
sed -n '
/User logged in/ {
# 将登录时间存储到保持空间
h
# 跳过处理,继续读取下一行
b
}
/User logged out/ {
# 将注销时间追加存储到保持空间
H
# 交换模式空间和保持空间中的内容
x
# 提取并打印用户会话信息
s/\(.*\) - User logged in\n\(.*\) - User logged out/\1 - \2/
# 清空模式空间,准备处理下一行
x
}' logfile.txt
此 sed 命令链执行以下操作:
- 当匹配到 User logged in 时,将登录时间存储到保持空间中。
- 当匹配到 User logged out时,将注销时间追加到保持空间中,并交换模式空间和保持空间中的内容。
- 使用正则表达式提取用户会话信息,并打印出来。
- 清空模式空间,准备处理下一行。
s/\(.*\) - User logged in\n\(.*\) - User logged out/\1 - \2/
这个表达式的含义是:匹配包含用户登录时间和用户注销时间的两行,然后用这两个时间来替换整个匹配的部分。在替换操作中,\1 代表用户登录时间,\2 代表用户注销时间。
- (…):这是用来定义一个捕获组的语法,捕获组可以在替换操作中使用。
- .*:这是匹配任意字符(除了换行符)零次或多次的模式,表示匹配任意长度的字符串。
- \n:这是换行符的转义字符,表示匹配一个换行符。
- \1和 \2:这是对应于第一个和第二个捕获组的替换引用。捕获组是通过在正则表达式中使用括号来定义的,第一个捕获组就是第一个用括号包裹的部分,以此类推。在替换操作中,\1代表第一个捕获组,\2 代表第二个捕获组。
运行上述 sed 命令后,输出将是:
2024-06-01 12:34:56 - 2024-06-01 12:35:10
5.3.3 示例3 将文件的内容进行逆序输出
现有一个文件 filename 包含以下内容:
Line 1
Line 2
Line 3
可使用以下sed命令进行逆序
sed '1!G;h;$!d' filename
这个 sed 命令的操作过程是:
对于第一行,什么也不做,直接输出。
对于其他行,将当前行与前面的行合并,然后将当前行的内容复制到保持空间中,再将当前行删除。
当处理到最后一行时,将最后一行与前面的行合并,然后输出。
这样,就实现了逆序输出文件内容的效果。
请注意sed 是依次循环执行filename文件中的每一行内容的。
以下是每个命令的解释:
-
1!G:
对于非第一行(即第二行及之后的行),执行命令 G,它的作用是将保持空间中的内容追加到模式空间中。
在 sed 中,每一行被读入时都会被存储在模式空间中。而 G 命令则是将保持空间中的内容(通常是前面行的内容)追加到模式空间中,并在两者之间添加一个换行符。
因此,这个命令的作用是将当前行与前面的行合并,实现了逆序的效果。 -
h:
h 命令将当前行的内容复制到保持空间中,以便在后续处理中使用。
在本例中,它的作用是将每一行的内容复制到保持空间中,以备后续使用。 -
$!d:
对于非最后一行,执行命令 d,它的作用是删除模式空间中的内容,即删除当前行。
$ 是 sed 中表示最后一行的符号,因此 $! 表示非最后一行。
这个命令的作用是删除模式空间中的当前行,因为在前面的步骤中,我们已经将当前行与前面的行合并,所以不需要保留当前行的内容了。