在成千上万的文件中搜索并替换数百个字符串?

时间:2010-04-21 02:41:02

标签: regex replace multiple-files

我正在考虑更改我工作的(C / C ++)项目中数百个文件的文件名。问题是我们的软件有成千上万的文件,包括(即#include)这些数百个将被改变的文件。这看起来像是一场维护噩梦。如果我这样做,我将被困在Ultra-Edit中数周,手动滚动数百个正则表达式:

^\#include.*["<\\/]stupid_name.*$

#include <dir/new_name.h>

这样的苦差事比用南瓜在南极的沉没潜艇上用勺子剥掉数百个土豆更糟糕。 我认为将输入和输出放入如下表格中是理想的:

stupid_name.h <-> <dir/new_name.h>
stupid_nameb.h <-> <dir/new_nameb.h>
stupid_namec.h <-> <dir/new_namec.h>

并将其提供给正则表达式引擎/工具/ app / etc ......

我的终极问题:是否有工具可以做到这一点?

奖金问题:它是多线程的吗?

我在本网站上查看了相当多的搜索和替换主题,并发现了许多标准查询,询问了以下问题的变体:

标准问题:在N个文件中替换一个术语。

而不是:

我的问题:替换N个文件中的N个术语。

提前感谢您的回复。

7 个答案:

答案 0 :(得分:2)

我会使用awk,一个类似于sed的命令行工具。

mv file.x file.x.bak;
awk '{
  gsub( "#include \"bad_one.h\"" , "#include \"good_one.h\"" );
  gsub( "#include \"bad_two.h\"" , "#include \"good_two.h\"" );
}' file.x.bak > file.x;

到达终端后,使用man awk查看更多详细信息。

答案 1 :(得分:1)

我认为您将旧/新名称放在一个位置的想法很好。它肯定会减少维护和验证变更的难度。看起来这是明显的答案,但我认为使用任何流行的脚本语言,如ruby,python,perl等,会使这项任务相当简单。该脚本可以读取具有旧/新替换信息的文件,从中构造适当的正则表达式,然后处理需要替换的文件。

该脚本可以编写为多线程实用程序,尽管在这种情况下似乎不会有很多好处。如果我理解这个问题,这基本上应该是一次性使用,所以高性能似乎不是首要任务。

答案 2 :(得分:1)

创建一系列perl单行来编辑文件,如下所示:

perl -i.bak -p -e 's/stupid_old_name/cool_new_name/' *.c

这还有额外的好处,即使用.bak扩展名保存任何已更改文件的原件。

如果我不熟悉perl,我会做出一些这样的事情。我甚至把所有的单行内容都放到了shell脚本中,但是我并没有试图给任何一个unix灰胡子留下深刻印象。

本网站很好地解释了perl的编辑: http://www.rice.edu/web/perl-edit.html

PS - 因为我相当了解perl,所以我只是在一个“真正的”perl脚本中编写was / is表,并用它来打开并解析所有文件。

答案 3 :(得分:1)

正如马克·威尔金斯所说,这是一个可行的计划,你喜欢任何正则表达式的脚本编写工具,但我建议另外几点:

  1. 使用两个脚本:一个用于将列表转换为正则表达式,另一个用于应用它们。试图在一个脚本中完成这两项工作就是在寻找麻烦。
  2. 不要忘记更改#include指令并同时重命名头文件。
  3. 如果你知道如何改变N个文件中的一个东西,那么,你可以只循环你要改变的K个东西。就处理器时间而言,这不是最有效的方式,但这不是瓶颈。
  4. 这种方法在理论上是有效的,但如果它在第一次尝试时在实践中起作用,那么你的代码库比我见过的任何东西(那个大小)更清晰。几乎肯定会有一些惊喜:一个与正则表达式不匹配的硬编码路径,一个与一个好名字相撞的坏名称,一些其他人没想到的故障。我建议从一对或两对名字开始小,每次更换后编译,并在遇到麻烦时撤退。如果你这样做,你可以将它设置为一夜之间运行,早上你将拥有一个几乎完成的工作代码库,以及一个引起麻烦并需要人工关注的名称列表。

答案 4 :(得分:0)

this(Wingrep)会不会这样做?

答案 5 :(得分:0)

在* nix,(或GNU win32)中,你可以一起使用GNU find和sed ...例如

find /path -type f -name "*.c" -exec  sed -i.bak 's/^\#include.*["<\\/]stupid_name.*$/#include <dir\/new_name.h>/' "{}" +;

解释,

find命令从-type f开始查找文件(/path)。 -name "*.c"搜索所有.c个文件,然后对于找到的每个文件,执行sed将字符串更改为新字符串。 -i.bak要求sed将原始文件保存为备份,然后再进行就地编辑。 "{}"表示传递给sed

的文件

答案 6 :(得分:0)

PowerGREP可以做到这一点。它可以在任何文件组合中搜索多个搜索字符串(文字文本或正则表达式),并且是多线程的(从PowerGREP 4开始,当前版本)。

alt text http://img682.imageshack.us/img682/5172/screen006c.png

您也可以保存搜索内容以供日后重复使用。