在多个文件中查找/替换的最佳方法是什么?

时间:2009-02-09 18:48:07

标签: shell replace find

最好的方法是什么?我不是命令行战士,但我认为有可能使用grep和cat。

我只想替换文件夹和子文件夹中出现的字符串。最好的方法是什么?如果重要的话,我正在运行ubuntu。

-d

6 个答案:

答案 0 :(得分:37)

正如保罗所说,您希望首先找到要编辑的文件,然后进行编辑。使用find的另一种方法是使用GNU grep(Ubuntu上的默认值),例如:

grep -r -l from . | xargs -0 -n 1 sed -i -e 's/from/to/g'

你也可以使用ack-grep(sudo apt-get install ack-grep或访问http://petdance.com/ack/),如果你知道你只想要某种类型的文件,并且想要忽略版本控制中的东西目录。例如,如果您只想要文本文件,

ack -l --print0 --text from | xargs -0 -n 1 sed -i -e 's/from/to/g'
# `from` here is an arbitrary commonly occurring keyword

使用sed的另一种方法是使用perl,它可以为每个命令处理多个文件,例如,

grep -r -l from . | xargs perl -pi.bak -e 's/from/to/g'

在这里,perl被告知要进行编辑,先制作一个.bak文件。

根据您的偏好,您可以将管道的任何左侧与右侧组合。

答案 1 :(得分:36)

find . -type f -print0 | xargs -0 -n 1 sed -i -e 's/from/to/g'

第一部分是find命令,用于查找要更改的文件。您可能需要适当地修改它。 “xargs”命令获取find找到的每个文件,并对其应用“sed”命令。 “sed”命令接受“from”的每个实例,并用“to”替换它。这是一个标准的正则表达式,因此请根据需要进行修改。

如果您使用svn当心。您的.svn目录也将被搜索和替换。你必须排除那些,例如:

find . ! -regex ".*[/]\.svn[/]?.*" -type f -print0 | xargs -0 -n 1 sed -i -e 's/from/to/g'

find . -name .svn -prune -o -type f -print0 | xargs -0 -n 1 sed -i -e 's/from/to/g'

答案 2 :(得分:28)

我将为使用Ag, The Silver Searcher对多个文件执行查找/替换操作的人员提供另一个示例。

完整示例:

ag -l "search string" | xargs sed -i '' -e 's/from/to/g'

如果我们打破这个,我们得到的是:

# returns a list of files containing matching string
ag -l "search string"

接下来,我们有:

# consume the list of piped files and prepare to run foregoing command
# for each file delimited by newline
xargs

最后,字符串替换命令:

# -i '' means edit files in place and the '' means do not create a backup
# -e 's/from/to/g' specifies the command to run, in this case,
# global, search and replace

sed -i '' -e 's/from/to/g'

答案 3 :(得分:3)

sed的替代方法是使用rpl(例如,可从http://rpl.sourceforge.net/或您的GNU / Linux发行版获得),例如rpl --recursive --verbose --whole-words 'F' 'A' grades/

答案 4 :(得分:2)

典型的 (find|grep|ack|ag|rg)-xargs-sed 组合有几个问题:

  • 难以记住和正确。例如,即使没有找到文件,忘记 xargs -r 选项也会运行命令,这可能会导致问题。
  • 检索文件列表和实际替换使用不同的 CLI 工具并且可以有不同的搜索行为。

这些问题对于递归搜索和替换这样的侵入性和危险操作来说已经足够大了,因此开始开发专用工具:mo

早期测试似乎表明它的性能介于 agrg 之间,并且解决了我遇到的以下问题:

  • 单个调用可以过滤文件名内容。以下命令在所有具有 v1 指示的源文件中搜索单词 bug

    mo -f 'src/.*v1.*' -p bug -w

  • 一旦搜索结果正常,就可以用fix实际替换bug

    mo -f 'src/.*v1.*' -p bug -w -r fix

答案 5 :(得分:0)

comment() { 
}
doc() { 
}
function agr { 
doc 'usage: from=sth to=another agr [ag-args]'
comment -l --files-with-matches

ag -0 -l "$from" "${@}" | pre-files "$from" "$to"
}
pre-files() {
doc 'stdin should be null-separated list of files that need replacement; $1 the string to replace, $2 the replacement.'
comment '-i backs up original input files with the supplied extension (leave empty for no backup; needed for in-place replacement.)(do not put whitespace between -i and its arg.)'
comment '-r, --no-run-if-empty
              If  the  standard input does not contain any nonblanks,
              do not run the command.  Normally, the command  is  run
              once  even  if there is no input.  This option is a GNU
              extension.'

AGR_FROM="$1" AGR_TO="$2" xargs -r0 perl -pi.pbak -e 's/$ENV{AGR_FROM}/$ENV{AGR_TO}/g'
}

您可以像这样使用它:

from=str1 to=sth agr path1 path2 ...

不提供任何路径使其使用当前目录。 请注意,需要在PATH上安装ag,xargs和perl。