【问题标题】:perl find and replace deleting filesperl 查找和替换删除文件
【发布时间】:2017-01-10 18:36:26
【问题描述】:

我是 Perl 脚本的新手,但我需要在数百个文件中执行大量正则表达式查找和替换。

我遇到了this website,它建议使用 Perl 命令 perl -p -i -e 's/oldstring/newstring/g' * 获取所有文件,然后使用 perl -p -i -e 's/oldstring/newstring/g' 'find ./ -name *.html\' 将其过滤到某些文件。

我的目标是找到所有 *.csproj 和 *.vbproj 文件并将对 .dll 的引用替换为新路径。

它们都是 XML 文件类型。

我要替换的文本是

<Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL">
  <SpecificVersion>False</SpecificVersion>
</Reference>

<Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL">
  <SpecificVersion>False</SpecificVersion>
  <Private>True</Private>
  <HintPath>..\..\..\..\ExternalDLLs\log4net.dll</HintPath>
</Reference>

到目前为止我的命令是

perl -p -i -e 's/<Reference Include="log4net, (?:.*?[\t\s\n\r])*?<\/Reference>/<Reference Include="log4net, Version=1\.2\.10\.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL"><SpecificVersion>False<\/SpecificVersion><Private>True<\/Private><HintPath>\.\.\\\.\.\\\.\.\\\.\.\\ExternalDLLs\\log4net\.dll<\/HintPath><\/Reference>/g'  `find . -type f \( -name "*.vbproj" -or -name "*.csproj" \)`

这似乎可以尝试,但最终会删除我所有的 *.vbproj 和 *.csproj 文件。

我不知道为什么我的脚本会删除文件。

有什么帮助吗?

编辑:每个文件都打印出来

Can't do inplace edit on ./Middletier/TDevAccess/AmCad.Components.TDevAccess.csproj: No such file or directory.

编辑 2:如果重要的话,我在 Windows 上的 Ubuntu 上使用 Bash

this 可以关联吗?

【问题讨论】:

    标签: regex perl


    【解决方案1】:

    如果你不小心的话,我建议你会以两种不同的方式绊倒自己。

    • 用正则表达式解析 XML 是个坏主意。这很混乱,因为regex 不是上下文相关的,而 XML 是。
    • Perl 有一个非常好的Find 模块,这意味着你不需要使用命令版本。

    我不知道您遇到问题的具体原因,但我猜这是因为find 命令正在生成换行符,而您没有剥离它们?

    无论如何,我建议您两者都不做,并使用XML::TwigFile::Find::Rule 在perl 中完成这项工作。

    类似:

    #!/usr/bin/perl
    use strict;
    use warnings;
    
    use File::Find::Rule;
    use XML::Twig;
    
    #setup the parser - note, this may reformat (in valid XML sorts of ways).
    my $twig = XML::Twig->new(
       pretty_print => 'indented',
    
       #set a handler for 'Reference' elements - to insert your values.
       twig_handlers => {
          'Reference' => sub {
             $_->insert_new_elt( 'Private' => 'True' );
             $_->insert_new_elt(
                'HintPath' => '..\..\..\..\ExternalDLLs\log4net.dll' );
    
             #flush is needed to write out the change.
             $_->flush;
          }
       }
    );
    
    #use rules to find suitable files to alter.
    foreach my $xml_file (
       File::Find::Rule->or(
          File::Find::Rule->name('*.csproj'),
          File::Find::Rule->name('*.vbproj'),
       )->in('.')
      )
    {
       print "\nFound: $xml_file\n";
    
       #do the parse.
       $twig->parsefile_inplace($xml_file);
    }
    

    从 cmets 开始 - 如果您想扩展以匹配 Reference 属性,有两种可能性 - 在 特定 xpath 上设置处理程序:

    twig_handlers => { '参考[@Include="log4net,版本=1.2.10.0,文化=中性,PublicKeyToken=1b44e1d426115821,处理器架构=MSIL"]' => sub { $_->insert_new_elt('私人' => '真'); $_->insert_new_elt( 'HintPath' => '........\ExternalDLLs\log4net.dll' );

         #flush is needed to write out the change.
         $_->flush;
      }
    

    }

    这是基于属性内容的选择(但请记住,上面的内容相当长且令人费解)。

    或者 - 处理程序为您遇到的每个引用“触发”,因此您可以构建测试。

    my $twig = XML::Twig->new(
       pretty_print => 'indented',
    
       #set a handler for 'Reference' elements - to insert your values.
       twig_handlers => {
          'Reference' => sub {
             #note - instead of 'eq' you can do things like regex tests. 
             if ( $_ -> att('Include') eq "log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL") {
                  $_->insert_new_elt( 'Private' => 'True' );
                  $_->insert_new_elt( 'HintPath' => '..\..\..\..\ExternalDLLs\log4net.dll' );
             }
    
             #flush is needed to write out the change.
             $_->flush;
          },
       }
    );
    

    【讨论】:

    • 我还没有运行它,但是从快速概览来看,它看起来像是找到了一个 XML 标记 Reference,并添加了子 HintPathPrivate,对吗?如果是这样,我如何限制它来查找属性设置为某个值的标签?
    • ie: Reference 标签有Include="log4net, Version=1.2.10.0...
    • 很容易。请耐心等待,我将更新示例。 xmltwig.org/xmltwig/quick_ref.html
    【解决方案2】:

    perl -pi 逐行处理输入文件。您的替换包含一个正则表达式,它试图匹配一些跨越多行的文本,因此它无法正常工作。您可以使用读取内存中的整个文件的-000 标志(即perl -000 -pie '.....')激活“slurp”模式。当然,您需要确保该目录中没有任何大文件。我不知道为什么文件会被删除,perl -i 确实重命名了原始文件,但这似乎不是问题所在。

    另外需要注意的是,如果任何文件的名称中包含空格,find ... 命令将失败,因此您可能会在执行命令之前执行IFS=$'\n' 之类的操作。

    【讨论】:

      猜你喜欢
      • 2015-10-06
      • 2014-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多