通过sed查找、替换文件中的文字

原文参见:通过sed查找、替换文件中的文字

处理文本文件时,经常需要在一个或多个文件中查找并替换文字。

sed是“stream editor”(直译为流编辑器),可以对文件和输入流(例如管道)执行基本的文字操作。使用sed可以搜索、查找和替换、插入和删除单词和行。sed支持基本的及扩展的正则表达式,可以匹配复杂的模式。

本文将讨论如何使用sed查找和替换字符串,还将展示如何执行递归搜索和替换。

用sed来查找并替换字符串

有多个版本sed,这些版本功能上会有所差别。macOS使用BSD版本,而大多数Linux发行版均默认预装有GNU版本sed。本文介绍的是GNU版本。

使用sed搜索、替换文本的一般形式为:

$ sed -i 's/SEARCH_REGEX/REPLACEMENT/g' INPUTFILE
  • -i – 默认情况下,sed输出到标准输出。此选项告诉sed编辑指定的文件。如提供了扩展名(例如-i.bak),将创建原始文件的备份。

  • s – 替代命令,应为sed最常用的命令。

  • / / / – 分隔符,可以是任何字符,通常使用斜杠(/)字符。

  • SEARCH_REGEX – 要搜索的字符串或正则表达式。

  • REPLACEMENT – 要替换成的字符串。

  • g – 全局替换标志。默认情况下,sed一行一行地读取文件,且仅更改行中第一次出现的SEARCH_REGEX。提供此替换标志后,所有找到的待替换字串都会被替换。

  • INPUTFILE – 运行sed命令的文件名。

好的命令习惯是在搜索替换参数上加引号,这样Shell的元字符不会按保留字符进行解析。

来看一个示例,具体看一下如何使用sed命令搜索、替换文件中一些常用的选项和标志。

出于演示目的,文件内容为:

file.txt

123 Foo foo foo foo /bin/bash Ubuntu foobar 456

如省略g标志,则仅替换每行中搜索字符串的第一个实例:

$ 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

有可能会注意到,前面的示例中,字符串foo内的子字符串foobar也被替换了。如果不想替换子字符串,在搜索字符串的两端使用单词边界表达式(\b),这样将只进行全字匹配,确保部分单词不会被匹配上。

$ sed -i 's/\bfoo\b/linux/g' file.txt

运行命令后,文件修改为:

123 Foo linux linux linux /bin/bash Ubuntu foobar 456

如匹配过程不区分大小写,请使用I标志。下面的示例同时使用g和I标志:

​
123 Foo linux linux linux /bin/bash Ubuntu foobar 456

 

文件修改为:

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编辑文件之前先进行备份是一个好习惯。为此需提供-i选项。例如,要编辑file.txt并保存原文件为file.txt.bak,请使用以下命令:

$ sed -i.bak 's/foo/linux/g' file.txt

要确认是否备份文件已创建,可使用以下ls命令列出文件:

​
$ sed -i.bak 's/foo/linux/g' file.txt

递归查找、替换

有时想递归地在目录中搜索包含字符串的文件,并替换所有文件中的字符串,可以使用find或grep命令来递归地在目录中查找文件,并将文件名传递给sed来进行。

以下命令将在当前工作目录中递归搜索文件,并将文件名传递给sed。

$ find . -type f -exec sed -i 's/foo/bar/g' {} +

为避免名称中包含空格的文件出现,请使用-print0选项,该选项告诉find打印文件名并跟随一个空格,然后使用xargs -0通过输出管道传递给sed:

$ find . -type f -print0 | xargs -0 sed -i 's/foo/bar/g'

要排除目录,可使用-not -path选项。例如,如果要替换本地git存储库中的字符串,但排除所有以点(.)开头的文件,命令为:

$ find . -type f -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:

$ find . -type f -name "*.md" -print0 | xargs -0 sed -i 's/foo/bar/g'

最后

看起来可能有些复杂,但开始尝试后就会发现使用sed搜索、替换文件中的文本实际上非常简单。

要了解sed命令、选项和标志的更多信息,请访问GNU sed手册Grymoire sed教程。如果有任何疑问或反馈,欢迎发表评论。

    原文作者:mareden
    原文地址: https://blog.csdn.net/mareden/article/details/107098101
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞