文本替换是其最常用的功能之一sed命令。当您需要替换大型文件或输入流中的文本模式实例而无需手动编辑每个实例时,此功能非常有用。
文本替换的基本语法sed
is:
sed 's/search_pattern/replacement_text/g' filename
在这个结构中:
-
s
表明我们正在执行替换。
-
search_pattern
标识您要替换的字符序列。
-
replacement_text
分配您想要的新内容来代替搜索模式。
-
g
确保全局替换,这意味着每行中的每个出现都会被替换。没有g
,仅处理每行的第一个实例。
-
filename
表示您正在使用的目标文件。
默认情况下,sed
将修改后的内容发送到标准输出(您的终端)而不更改原始文件。
替换每行中出现的所有内容
假设您有一个名为sample.txt
包含以下内容:
Hello, world!
Hello, user!
Hello, admin!
现在,假设您想将每次出现的“Hello”替换为“Hi”。这样做的方法如下:
$ sed 's/Hello/Hi/g' sample.txt
Output:
Hi, world!
Hi, user!
Hi, admin!
这是我们刚刚所做的细分:
s
:表示替换操作。
Hello
:这是搜索模式。
Hi
:这是替换文本。
g
: 指示sed
替换一行中出现的所有内容。如果没有它,则只会替换每行中的第一个“Hello”。
如果您想将修改后的内容保存回文件,您可以重定向输出或使用 sed 的就地编辑选项
sed -i 's/Hello/Hi/g' sample.txt
仅替换每行中第一次出现的内容
您可以通过省略将文本替换限制为仅第一次出现g
标志在sed
命令。
考虑相同sample.txt
我们之前使用的文件:
Hello, world! Hello again.
Hello, user! Hello once more.
Hello, admin! Hello for the last time.
让我们仅将每行中的第一个“Hello”替换为“Hi”:
$ sed 's/Hello/Hi/' sample.txt
Output:
Hi, world! Hello again.
Hi, user! Hello once more.
Hi, admin! Hello for the last time.
通过删除g
flag, sed
只针对每行的第一个“Hello”,后续出现的内容保持不变。
使用分隔符
在基本语法中s/search_pattern/replacement_text/g
, 人物/
是分隔符。
它区分命令、搜索模式和替换。本质上,它讲述了sed
一个部分结束而另一部分开始的地方。
更改默认分隔符
如果您的模式或替换文本包含大量正斜杠(常见于文件路径或 URL),不断地用反斜杠转义它们可能会使您的命令难以阅读。
在这种情况下,您可以使用不同的分隔符。
让我们考虑一个您想要替换路径的现实场景/home/user/old_dir
with /home/user/new_dir
。使用默认分隔符将如下所示:
$ sed 's/\/home\/user\/old_dir/\/home\/user\/new_dir/g' filename.txt
这很混乱,不是吗?让我们将分隔符更改为#
:
$ sed 's#/home/user/old_dir#/home/user/new_dir#g' filename.txt
该命令更具可读性。您可以使用任何字符作为分隔符。
不区分大小写的替换
The I
标志与sed
使您能够执行不区分大小写的搜索和替换,确保您捕获特定模式的所有变体。
让我们使用一个示例文件,cases.txt
,包含:
Linux is great.
LINUX is powerful.
linux is open-source.
如果您想将“linux”的每个实例替换为“UNIX”,无论大小写,请按以下步骤操作:
$ sed 's/linux/UNIX/Ig' cases.txt
Output:
UNIX is great.
UNIX is powerful.
UNIX is open-source.
关于可移植性的快速说明:虽然I
标志适用于 GNUsed
(在 Linux 上常见),如果您使用的是 macOS 或 BSDsed
,你会使用i
代替旗帜。
限制更换数量
With sed
,您可以通过在替换命令后附加一个数字来将替换次数限制为特定计数,该数字指示要替换的目标的特定出现次数。
替换特定事件
给定一个文件,repeats.txt
,内容如下:
apple apple apple
banana banana banana
cherry cherry cherry
假设您只想将每个水果的第二次出现替换为“fruit”。就是这样:
$ sed 's/apple/fruit/2' repeats.txt
Output:
apple fruit apple
banana fruit banana
cherry fruit cherry
如果您想定位第三次出现,只需将数字更改为 3 即可。
转义特殊字符
特殊字符(通常称为元字符)在正则表达式中具有特定含义。
要将它们用作文字字符,或避免它们的特殊含义,您必须使用反斜杠“转义”它们(\
).
常见特殊字符
In sed
和正则表达式一样,有几个字符具有独特的作用:
-
.
: 匹配任意单个字符。
-
*
:匹配零个或多个前面的字符或组。
-
^
:将图案锚定到行的开头。
-
$
:将图案锚定到线条末端。
-
[...]
:匹配括号内的任一字符。
-
(
and )
:组模式。
转义特殊字符
要按字面意义使用这些字符中的任何一个sed
命令,在它们前面加上反斜杠。
例如,如果您有一个名为special.txt
内容:
end...end
start*start
start.end
而你想更换...
with ---
:
$ sed 's/\.\.\./---/g' special.txt
Output:
end---end
start*start
start.end
在这里,你正在逃避每个时期(.
) 带反斜杠以确保sed
将它们解释为文字点,而不是匹配任何字符的通配符。
同样,要替换*
with +
,你会使用:
$ sed 's/\*/+/g' special.txt
替换多个文件中的文本(sed 和 find)
The find
命令允许您在目录层次结构中搜索文件。将其与sed
允许您递归地替换多个文件中的文本。
假设您有一个包含各种文本文件的项目,并且您希望将“old_project”的所有实例替换为“new_project”。执行以下命令:
$ find /path/to/directory -type f -name "*.txt" -exec sed -i 's/old_project/new_project/g' {} +
分解组件:
-
find /path/to/directory
:在指定目录内搜索。
-
-type f
:仅针对文件。
-
-name "*.txt"
:将搜索过滤到.txt
files.
-
-exec
:对每个找到的项目执行命令。
-
sed -i 's/old_project/new_project/g'
: The sed
你熟悉的命令。这-i
旗帜告诉sed
就地编辑文件。
-
{} +
: 这个语法允许find
取代{}
找到的文件名,有效地将它们传递给sed
命令进行处理。
将 sed 与 xargs 结合使用以增强性能
在某些情况下,您要处理多个文件,使用xargs
将通过减少个体数量来提高性能sed
产生的进程:
$ find /path/to/directory -type f -name "*.txt" | xargs sed -i 's/old_project/new_project/g'
Here, xargs
从中获取文件列表find
并将它们喂给sed
分成更大的块,最大限度地减少进程开销。
基准 exec 与 xargs(xargs 更快)
使用以下方法对文件内容替换的速度进行基准测试sed
and find
with exec
and xargs
,我们有一个目录,其中包含 1000 个包含特定模式的文件。
让我们用另一个字符串替换该模式。
这是一个简单的分步指南:
- 创建一个包含大量包含特定模式的文件的目录。
- 使用以下方法测量更换图案所需的时间
find
with exec
.
- 使用以下方法测量更换图案所需的时间
find
with xargs
.
创建包含示例文件的目录:
mkdir benchmark_dir
cd benchmark_dir
# Create 1000 files with the content "replace_me"
for i in {1..1000}; do
echo "replace_me" > file_$i.txt
done
基准测试使用find
with exec
:
time find . -type f -name '*.txt' -exec sed -i 's/replace_me/replaced/g' {} \;
Output:
real 0m2.187s
user 0m1.258s
sys 0m0.825s
重置文件进行测试xargs
:
for i in {1..1000}; do
echo "replace_me" > file_$i.txt
done
基准测试使用find
with xargs
:
time find . -type f -name '*.txt' | xargs sed -i 's/replace_me/replaced/g'
Output:
real 0m0.271s
user 0m0.016s
sys 0m0.249s
从比较两种方法的实际时间可以看出,由于减少了进程创建的开销,xargs 比使用 exec 更快。