2016-09-02 59 views
2

我是新手Perl腳本編寫,但我需要做大量的正則表達式查找和替換跨越數百個文件。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:IM使用bash在Ubuntu在Windows上,如果該事項

this有關?

回答

3

我建議你會以兩種不同的方式絆倒自己,如果你不是很小心。

  • 用正則表達式解析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); 
} 

從評論繼 - 如果你想擴展到匹配Reference屬性,有兩家possiblities - 無論是設置在具體的XPath處理程序:

twig_handlers => { '參考[@include =「log4net,Version = 1.2.10。0,Culture = neutral,PublicKeyToken = 1b44e1d426115821,processorArchitecture = MSIL「]'=> sub {_insert_new_elt('Private'=>'True'); $ _-> 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; 
     }, 
    } 
); 
+0

我還沒有運行過這個功能,但是從快速瀏覽看來,它看起來像是在查找一個XML標籤'Reference',並添加了子項'HintPath'和'Private',是否正確?如果是這樣,我該如何限制它以查找具有設置爲特定值的屬性的標籤? –

+0

即:具有'Include =「log4net,版本= 1.2.10.0 ...' –

+0

的'Reference'標記足夠容易,忍受着我,我會更新這個例子http://xmltwig.org/xmltwig/quick_ref html的 – Sobrique

0

perl -pi逐行處理輸入文件。你的替換包含一個正則表達式,它試圖匹配跨越多行的一些文本,所以它不能正常工作。您可以使用-000標誌(即perl -000 -pie '.....')激活「slurp」模式,該標誌讀取存儲器中的整個文件。當然,您需要確保在該目錄中沒有任何大文件。我不知道爲什麼這些文件被刪除,perl -i確實重命名了原始文件,但這似乎並不是問題。

另一件需要注意的是,如果任何文件的名稱中包含空格,那麼find ...命令將會失敗,因此在執行該命令之前可能會這樣做IFS=$'\n'