最好的方法是什么?我不是命令行战士,但我在想可能有一种使用grep
and的方法cat
。
我只想替换文件夹和子文件夹中出现的字符串。最好的方法是什么?如果这很重要,我正在运行 ubuntu。
我将为使用ag
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'
find . -type f -print0 | xargs -0 -n 1 sed -i -e 's/from/to/g'
第一部分是查找命令,用于查找要更改的文件。您可能需要适当地修改它。该xargs
命令获取找到的每个文件并将该sed
命令应用于它。该命令获取fromsed
的每个实例并将其替换为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'
正如 Paul 所说,您要先找到要编辑的文件,然后再对其进行编辑。使用 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 文件。
您可以根据自己的喜好将管道的任何左侧与右侧组合起来。
一种替代方法sed
是使用rpl
(例如,可从http://rpl.sourceforge.net/或您的 GNU/Linux 发行版获得),例如rpl --recursive --verbose --whole-words 'F' 'A' grades/
典型的(find|grep|ack|ag|rg)-xargs-sed
组合有几个问题:
xargs -r
例如,即使没有找到文件,忘记该选项也会运行命令,这可能会导致问题。这些问题对于递归搜索和替换这样的侵入性和危险操作来说已经足够大,以至于开始开发专用工具:mo。
早期的测试似乎表明它的性能介于ag和rg之间,它解决了我遇到的以下问题:
一次调用可以过滤文件名和内容。以下命令在所有带有v1指示的源文件中搜索单词bug :
mo -f 'src/.*v1.*' -p bug -w
一旦搜索结果正常,就可以添加实际的bug替换:
mo -f 'src/.*v1.*' -p bug -w -r fix
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。