簡體   English   中英

perl搜索並替換子字符串

[英]perl search and replace a substring

我正在嘗試搜索子字符串,並在找到子字符串時替換整個字符串。 在下面的例子中,someVal可以是我不知道的任何值。

我如何搜索someServer.com並替換整個字符串$ oldUrl和$ newUrl?

我可以在整個字符串上做到這一點:

$directory = "/var/tftpboot";

my $oldUrl = "someVal.someServer.com";
my $newUrl = "someNewVal.someNewServer.com";

opendir( DIR, $directory ) or die $!;
while ( my $files = readdir(DIR) ) {
    next unless ( $files =~ m/\.cfg$/ );
    open my $in,  "<", "$directory/$files";
    open my $out, ">", "$directory/temp.txt";
    while (<$in>) {
        s/.*$oldUrl.*/$newUrl/;
        print $out $_;
    }
    rename "$directory/temp.txt", "$directory/$files";
}

您的腳本將刪除大部分內容,因為您將匹配.* 這將匹配除換行之外的任何字符,從每行的開始到結束,盡可能多次匹配,並替換它。

您在Perl中已經存在的功能,使用-pi命令行切換,因此最好使用它而不是嘗試創建自己的功能,它的工作方式完全相同。 您不需要使用單線程來使用就地編輯。 你可以這樣做:

perl -pi script.pl *.cfg

該腳本應包含名稱定義和替換,以及您需要的任何錯誤檢查。

my $old = "someVal.someServer.com";
my $new = "someNewVal.someNewServer.com";

s/\Q$old\E/$new/g;

如上所示,當使用-pi開關運行時,這是最簡單的解決方案。 \\Q ... \\E是quotemeta轉義符,它會轉義字符串中的元字符(強烈推薦)。

您可能希望阻止部分匹配。 如果您匹配foo.bar ,則可能不希望匹配foo.bar.bazsnafoo.bar 為了防止部分匹配,您可以放入不同類型的錨點。

  • (?<!\\S) - 匹配前不允許任何非空格
  • \\b - 匹配單詞邊界

如果要在上面的示例中替換server1.foo.bar ,而不是snafoo.bar ,則Word邊界將是合適的。 否則使用空白邊界。 我們使用負面外觀斷言和否定字符類進行雙重否定的原因是允許行匹配的開始和結束。

所以,總結一下,我會這樣做:

use strict;
use warnings;

my $old = "someVal.someServer.com";
my $new = "someNewVal.someNewServer.com";

s/(?<!\S)\Q$old\E(?!\S)/$new/g;

並運行它

perl -pi script.pl *.cfg

如果你想事先嘗試一下(強烈推薦!),只需刪除-i開關,這將使腳本打印到標准輸出(你的終端)。 然后,您可以在文件上運行差異以檢查差異。 例如:

$ perl -p script.pl test.cfg > test_replaced.cfg
$ diff test.cfg test_replaced.cfg

您將不得不決定是否更需要字邊界,在這種情況下,您可以用\\b替換環繞聲斷言。

一直用

use strict;
use warnings;

即使是像這樣的小腳本。 它將為您節省時間和頭痛。

如果要匹配和替換任何子域,則應設計特定的正則表達式以匹配它們。

\b(?i:(?!-)[a-z0-9-]+\.)*someServer\.com

以下是使用更多Modern Perl技術重寫腳本,包括Path::Class以跨平台方式處理文件和目錄操作, $INPLACE_EDIT自動處理文件編輯。

use strict;
use warnings;
use autodie;

use Path::Class;

my $dir = dir("/var/tftpboot");

while (my $file = $dir->next) {
    next unless $file =~ m/\.cfg$/;

    local @ARGV = "$file";
    local $^I = '.bak';
    while (<>) {
        s/\b(?i:(?!-)[a-z0-9-]+\.)*someServer\.com\b/someNewVal.someNewServer.com/;
        print;
    }
    #unlink "$file$^I"; # Optionally delete backup
}

觀察Dot-Star:它匹配舊URL周圍的所有內容,因此該行唯一剩下的就是新的URL:

s/.*$oldUrl.*/$newUrl/; 

更好:

s/$oldUrl/$newUrl/;

此外,您可能需要在嘗試重命名之前close輸出文件。

如果舊URL包含特殊字符(點,星號,美元符號......),則可能需要使用\\Q$oldUrl來抑制其在正則表達式模式中的特殊含義。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM