sed 是一个轻量级 stream 流编辑器。它可以对文件和输入流(例如管道)执行基本的文本操作。
您可以使用 sed 进行搜索,查找和替换,插入和删除字符串和行。它支持基本和扩展的正则表达式,使您可以匹配复杂的模式。
在本教程中,我们将讨论如何在 Linux 使用 sed 查找和替换字符串。我们还将向您展示如何执行递归搜索和替换。
sed 搜索并替换字符串
sed
有多个版本,它们之间在功能上有所不同。MacOS 使用 BSD 版本,并且大多数 Linux 发行版均默认预装 GNU sed。我们将使用 GNU 版本。
使用 sed 搜索和替换文本采用采用以下语法形式:
sed -i 's/SEARCH_REGEX/REPLACEMENT/g' INPUTFILE
-i
选项指示sed
直接编辑文件。默认情况下,sed
将其输出写入到标准输出。如果提供扩展名(例如-i.bak),sed 会创建原始文件的备份。s
是替换命令,是 sed 最常用的命令。/
分隔符。它可以是任意字符,但通常使用斜杠/
作为分隔符。SEARCH_REGEX
要搜索的字符串或正则表达式。REPLACEMENT
使用此字符串进行替换。g
全局替换标志。默认情况下,sed
逐行读取文件,并且仅修改文件行中与搜索模式匹配第一次出现的字符。提供 g 替换标志后,所有匹配项都将被替换。INPUTFILE
要执行替换,删除,编辑等操作文件的名称。
sed 命令最佳实践是表达式周围加上引号,转义 Shell 元字符,避免 Shell 的解释 这里的表达式指的是 's/SEARCH_REGEX/REPLACEMENT/g'
。
让我们看一下如何在 Linux 使用 sed 命令搜索和替换文件中字符串或者文本。出于演示目的,我们将使用 file.txt 文件:
123 Foo foo foo
foo /bin/bash Ubuntu foobar 456
如果省略 g
标志,则仅替换每行与搜索模式匹配第一个字符串。sed -i 's/foo/linux/' file.txt 命令将会使用 linux 替换 foo:
sed -i 's/foo/linux/' file.txt
123 Foo linux foo
linux /bin/bash Ubuntu foobar 456
当使用全局替换标志 g, sed 替换所有与搜索模式匹配的字符串:
sed -i 's/foo/linux/g' file.txt
123 Foo linux linux
linux /bin/bash Ubuntu linuxbar 456
您可能已经注意到,在前面的示例中,字符串 foobar
内的子字符串 foo
也被替换了。
如果这不是你想要的行为,请在搜索字符串的两端使用单词边界表达式 \b
。这样可以确保单词的部分不被匹配。
sed -i 's/\bfoo\b/linux/g' file.txt
123 Foo linux linux
linux /bin/bash Ubuntu foobar 456
要使搜索模式的匹配不区分大小写,请使用 sed 的 I
选项。在下面的示例中,我们同时使用 g
和 I
选项进行搜索替换:
sed -i 's/foo/linux/gI' file.txt
123 linux linux linux
linux /bin/bash Ubuntu linuxbar 456
如果你要搜索替换的字符串包含分隔符 /
,则需要使用反斜杠 \
来转义斜杠 /
。例如替换 /bin/bash
为 /usr/bin/zsh
,请运行以下命令:
sed -i 's/\/bin\/bash/\/usr\/bin\/zsh/g' file.txt
更简单易读的选项是使用另一个字符作为分隔符。大多数人使用竖线 |
或冒号 :
作为分隔符,但也您可以使用你喜欢的任意字符:
sed -i 's|/bin/bash|/usr/bin/zsh|g' file.txt
123 Foo foo foo
foo /usr/bin/zsh Ubuntu foobar 456
您也可以使用正则表达式。例如,搜索连续的 3 个数字并将其替换为 number
,请运行以下命令:
sed -i 's/\b[0-9]\{3\}\b/number/g' file.txt
number Foo foo foo
foo /bin/bash demo foobar number
sed 的另一个非常有用功能是您可以使用 &
符号记住搜索模式匹配的值,然后在后面引用它。
你可以多次使用 &
符号。例如,如果要在与搜索模式匹配的 3 个数字周围添加花括号 {}
,请运行以下命令:
sed -i 's/\b[0-9]\{3\}\b/{&}/g' file.txt
{123} Foo foo foo
foo /bin/bash demo foobar {456}
最后但并非最不重要的一点是,使用 sed 编辑文件时,先进行备份是一个良好习惯。要备份原始文件,只需在 sed 命令的 -i
选项指定备份文件的后缀名即可。
例如,要编辑 file.txt
并备份原始文件名为 file.txt.bak
。请运行以下命令:
sed -i.bak 's/foo/linux/g' file.txt
如果要确保是否已创建原始文件的备份,请运行 ls
命令列出文件:
ls
file.txt file.txt.bak
递归查找和替换
有时您想在目录中进行递归搜索包含指定字符串的文件,并且使用指定的字符串替换所有文件。
可以通过 find 命令遍历目录的所有文件,然后通过 -exec 选项运行 sed 命令来完成对文件中字符串的搜索与替换。
以下命令将递归遍历当前工作目录的所有文件,并将文件名传递给 sed 将 bar 全局替换 为 foo。
find . -type f -exec sed -i 's/foo/bar/g' {} +
为避免文件名中包含空格的问题,请使用 find 命令 -print0
选项,该选项指示 find 命令后跟一个空字符打印文件名。
然后将 find 命令的标准输出通过管道传递给 xargs
命令。xargs 命令将会为 sed 命令提供最后一个参数文件名。
此处的 xargs
命令的 -0 选项是告诉 xargs 命令,传递给 xargs 命令的参数没有使用任何分隔符分隔参数,因为 find 使用了 -print0
选项。
因此最终的命令是 find . -type f -print0 | xargs -0 sed -i 's/foo/bar/g'。
find . -type f -print0 | xargs -0 sed -i 's/foo/bar/g'
要排除目录,请使用find 命令 -not -path 选项。例如,如果要替换本地 git 仓库以点 .
开头的文件,请运行以下命令:
find . -type f -not -path '*/\.*' -print0 | xargs -0 sed -i 's/foo/bar/g'
如果只是想搜索并替换具有指定扩展名的文件的内容,则可以运行以下命令:
find . -type f -name "*.md" -print0 | xargs -0 sed -i 's/foo/bar/g'
另一种选择是使用 grep 命令以递归方式搜索包含搜索模式的所有文件,然后将文件名通过管道传递给 sed
命令对文件内容进行搜索替换:
grep -rlZ 'foo' . | xargs -0 sed -i.bak 's/foo/bar/g'
结论
尽管看似复杂,但一开始,使用 sed 搜索和替换文件中的文本非常简单。要了解 sed 命令,选项和标志的更多信息。
请访问 GNU sed手册 和 Grymoire sed 教程。如果您有任何问题或反馈,请随时发表评论。