正则表达式替换多个文件

时间:2013-03-04 09:41:54

标签: regex linux sed awk

我需要将一个正则表达式的所有实例替换为根目录下多个目录中的多个文件中的另一个正则表达式。

实施例: 文件结构:

.
|---src
|   |---Module
|   |   |---someclass.cpp
|   |---main.cpp
|
|---include
    |---Module
        |---someclass.hpp

基本上是这样但有更多的文件和文件夹。

我需要搜索正则表达式\(std::vector<.*>并用\(std::vector<.*> const&替换它的所有实例 棘手的部分似乎是确保<>之间的内容保持不变。

例如,它会匹配(std::vector<int>并将其替换为(std::vector<int> const&。 一个更复杂的例子是:
匹配:(std::vector<std::map<std::string, int>>
替换为:(std::vector<std::map<std::string, int>> const&

2 个答案:

答案 0 :(得分:4)

如果最终“&gt;”在你的例子中是最后一个“&gt;”在每一行上,这应该工作:

find root -name '*.cpp' -print0 |
xargs -0 sed -i 's/\((std::vector<.*>\)\([^>]*$\)/\1 const\&\2/'

在单个文件上尝试使用sed而不使用-i,例如:

$ cat file
(std::vector<int>
(std::vector<int> foo
(std::vector<std::map<std::string, int>>
(std::vector<std::map<std::string, int>> bar

$ sed 's/\((std::vector<.*>\)\([^>]*$\)/\1 const\&\2/' file
(std::vector<int> const&
(std::vector<int> const& foo
(std::vector<std::map<std::string, int>> const&
(std::vector<std::map<std::string, int>> const& bar

如果在您的示例中最后一个之后可以有“&gt;”s,则解决方案非常重要,发布一些有代表性的示例输入和预期输出。

哦,到底是什么,这是非平凡的剧本:

$ cat file
(std::vector<int>
(std::vector<int> foo
(std::vector<int> with extra > in text
(std::vector<std::map<std::string, int>>
(std::vector<std::map<std::string, int>> bar
(std::vector<std::map<std::string, int>> and here is > again

$ awk -v FS= -v str="(std::vector<" '
BEGIN{ lgth=length(str) }
start=index($0,str) {
   cnt = 1
   for(i=(start+lgth);(i<=NF) && (cnt!=0);i++) {
      if ($i == "<") cnt++
      if ($i == ">") cnt--
   }
   $0 = substr($0,1,i-1) " const&" substr($0,i)
}1' file
(std::vector<int> const&
(std::vector<int> const& foo
(std::vector<int> const& with extra > in text
(std::vector<std::map<std::string, int>> const&
(std::vector<std::map<std::string, int>> const& bar
(std::vector<std::map<std::string, int>> const& and here is > again

在while循环中执行此操作:

find root -name '*.cpp' -print |
while IFS= read -r file; do
    awk -v FS= -v str="(std::vector<" '
    BEGIN{ lgth=length(str) }
    start=index($0,str) {
       cnt = 1
       for(i=(start+lgth);(i<=NF) && (cnt!=0);i++) {
          if ($i == "<") cnt++
          if ($i == ">") cnt--
       }
       $0 = substr($0,1,i-1) " const&" substr($0,i)
    }1' "$file" > tmp &&
    mv tmp "$file"
done

如果您的文件名包含换行符,那将无效,但如果您拥有换行符,则应该修复它们。

答案 1 :(得分:0)

您需要使用不同的正则表达式分别处理简单和复杂的情况。正则表达式不能计算嵌套项并考虑到它。

替换为无嵌套:\(std\:\:vector\<([^\<\>]*)\>

然后用单一嵌套替换:\(std\:\:vector\<([^\<\>]*\<[^\<\>]*\>[^\<\>]*)\>