代码之家  ›  专栏  ›  技术社区  ›  Michael Kristofik

Linux命令行全局搜索和替换

  •  78
  • Michael Kristofik  · 技术社区  · 15 年前

    我正在尝试搜索并替换与grep匹配的所有文件中的字符串:

    grep -n 'foo' *

    [filename]:[line number]:[text]
    

    对于grep返回的每个文件,我想通过替换 foo 具有 bar .

    8 回复  |  直到 4 年前
        1
  •  108
  •   greduan    8 年前

    根据您给出的示例,这似乎是您想要的:

    sed -i 's/foo/bar/g' *
    

    它不是递归的(它不会下降到子目录)。要获得一个很好的解决方案,在整个树中替换选定的文件,我将使用查找:

    find . -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;
    

    *.html 是文件必须匹配的表达式 .bak 之后 -i 制作原始文件的副本,扩展名为.bak(可以是您喜欢的任何扩展名)和 g 在sed表达式的末尾,它告诉sed替换一行上的多个副本(而不仅仅是第一个副本)。这个 -print

        2
  •  70
  •   armandino rampion    12 年前

    您的意思是在所有与grep匹配的文件中搜索并替换字符串吗?

    perl -p -i -e 's/oldstring/newstring/g' `grep -ril searchpattern *`
    

    因为这似乎是一个相当流行的问题,所以我想更新一下。

    现在我主要使用 ack-grep

    perl -p -i -e 's/old/new/g' `ack -l searchpattern`
    

    要处理文件名中的空白,可以运行:

    ack --print0 -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'
    

    阿克格雷普 . 假设您只想将搜索限制为HTML文件:

    ack --print0 --html -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'
    

    如果空白不是一个问题,它甚至更短:

    perl -p -i -e 's/old/new/g' `ack -l --html searchpattern`
    perl -p -i -e 's/old/new/g' `ack -f --html` # will match all html files
    
        3
  •  14
  •   Keltia    15 年前

    sed(1) 有一个 -i 选项,然后按如下方式使用:

    for i in *; do
      sed -i 's/foo/bar/' $i
    done
    

    ruby -i.bak -pe 'sub(%r{foo}, 'bar')' *
    perl -pi.bak -e 's/foo/bar/' *
    
        4
  •  6
  •   glenn jackman    13 年前

    我喜欢并使用上述解决方案,或在数千个文件中进行系统范围的搜索和替换:

    find -name '*.htm?' -print -exec sed -i.bak 's/foo/bar/g' {} \;
    

    我假设它使用“*.htm”而不是.html来搜索和查找.htm和.html文件。

    我将.bak替换为系统范围内更广泛使用的tilde(~),以便更轻松地清理备份文件。

        5
  •  4
  •   pymarco    11 年前

    grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @
    
        6
  •  3
  •   Eugene Yarmash    13 年前

    find . -type f -print0 | xargs -0 <sed/perl/ruby cmd> 将一次处理多个包含空格的文件名,每批加载一个解释器。快得多。

        7
  •  1
  •   jlevy    9 年前

    已经给出了使用的答案 发现

    find -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;

    这可能是标准答案。或者你可以用 perl -pi -e s/foo/bar/g' 而不是 sed 命令

    对于大多数快速使用,您可以找到以下命令 更容易记住。以下是当前目录中所有文件的递归替换(foo->bar):

    rpl -R foo bar .

    默认情况下,它在大多数Linux发行版上都不可用,但可以快速安装( apt-get install rpl

    然而,对于涉及正则表达式和反向替换、文件重命名以及搜索和替换的更为困难的工作,我所知道的最通用、最强大的工具是 雷普伦 ,一个小Python脚本,我不久前为一些更棘手的重命名和重构任务编写的。您选择它的原因可能是:

    • 在承诺执行搜索和替换之前,请查看更改。

    Check the README 例如。

        8
  •  1
  •   siliconrockstar    8 年前

    这实际上比看起来容易。

    grep -Rl 'foo' ./ | xargs -n 1 -I % sh -c "ls %; sed -i 's/foo/bar/g' %";
    
    • grep在树(-R)中递归,只打印文件名(-l),从当前目录(./)开始
    • 它通过管道传输到xargs,xargs一次处理一个(-n1),并在shell命令(sh-c)中使用%作为占位符(-I%)
    • 在shell命令中,首先打印文件名(ls%;)

    简单的豌豆。如果您很好地掌握了find、grep、xargs、sed和awk,那么在bash中处理文本文件几乎没有什么是不可能的:)