【问题标题】:Search and replace a string in a file搜索和替换文件中的字符串
【发布时间】:2019-09-01 20:15:11
【问题描述】:

我正在尝试从输入文件中读取内容,仅从文件中复制某些代码行并打印到输出文件中。

某些代码行由以下因素决定:

  1. 确定第一行的代号(IP1_NAME 或 IP2_NAME)
  2. 确定最后一行的模式 (END_OF_LIST)

输入文件:

IP1_NAME    
   /ip1name/ip1dir/ //CLIENT_NAME/ip1name/ip1dir
   /ip1testname/ip1testdir/ //CLIENT_NAME/ip1testname/ip1testdir
END_OF_LIST
IP2_NAME
   /ip2name/ip2dir/ //CLIENT_NAME/ip2name/ip2dir
   /ip2testname/ip2testdir/ //CLIENT_NAME/ip2testname/ip2testdir
END_OF_LIST

输出文件:

(如果选择了 IP1_NAME 并且 CLIENT_NAME 应替换为 tester_ip)

/ip1name/ip1dir/ //tester_ip/ip1name/ip1dir
/ip1testname/ip1testdir/ //tester_ip/ip1testname/ip1testdir

【问题讨论】:

    标签: perl


    【解决方案1】:

    您可以使用以下单线画出两个图案之间的线条:

    perl -0777 -ne 'print "$1\n" while /IP1_NAME(.*?)END_OF_LIST/gs' in.txt > out.txt
    

    in.txt 是您的输入文件,out.txt 是输出文件。

    这个用例实际上在perlfaq6: Regular Expressions中有所描述。

    然后您可以修改输出文件以将CLIENT_NAME 替换为tester_ip

    perl -pi -e 's/CLIENT_NAME/tester_ip/' y.txt
    

    【讨论】:

    • 感谢专线小巴。我正在使用脚本来搜索和替换上面描述的内容。如何在脚本中使用单行。这是一个 perl 脚本。
    • @RajeshMurugesan:哦,好的,您的原始问题中没有解释...您可能需要更新您的问题并显示脚本的相关部分。或者您也可以查看我的回答中的 perlfaq 链接,该链接提供了更多示例。
    【解决方案2】:

    作为脚本而不是单行,使用标量 range operator

    #/usr/bin/env perl
    use warnings;
    use strict;
    use autodie;
    use feature qw/say/;
    
    process('input.txt', qr/^IP1_NAME$/, qr/^END_OF_LIST$/, 'tester_ip');
    
    sub process {
      my ($filename, $startpat, $endpat, $newip) = @_;
      open my $file, '<', $filename;
      while (my $line = <$file>) {
        chomp $line;
        if ($line =~ /$startpat/ .. $line =~ /$endpat/) {
          next unless $line =~ /^\s/; # Skip the start and lines.
          $line =~ s/^\s+//; # Remove indentation
          $line =~ s/CLIENT_NAME/$newip/g; # Replace with desired value
          say $line;
        }
      }
    }
    

    在您的示例输入文件上运行它会产生:

    /ip1name/ip1dir/ //tester_ip/ip1name/ip1dir
    /ip1testname/ip1testdir/ //tester_ip/ip1testname/ip1testdir
    

    【讨论】:

    • 这对于一次性脚本来说很好。但是,如果您想在可能不止一次运行的东西中使用触发器,您需要确保避免这个陷阱:stackoverflow.com/questions/2143554/…(仍然相关)
    【解决方案3】:

    我假设您的输入文件中还有其他内容,否则我们不必用这些开始和结束标记跳过箍,我们可以说

    perl -ne "print if /^ /"
    

    那太傻了,对吧 ;-)

    所以,正如我在评论中所说,人字拖存在潜在问题。虽然很聪明,但它在可读性或冗长(冗长?)方面并没有给您带来太多好处,因为无论如何您都必须再次测试才能不处理标记线。

    只要没有独占触发器操作符,我会选择更健壮的解决方案。

    my $in;
    
    while (<DATA>) {
        $in = 1, next if /^IP\d_NAME/;
        $in = 0       if /^END_OF_LIST/;
    
        if ( $in )
        {
            s/CLIENT_NAME/tester_ip/;
            print;
        }
    }
    __DATA__
    cruft
    IP1_NAME    
       /ip1name/ip1dir/ //CLIENT_NAME/ip1name/ip1dir
       /ip1testname/ip1testdir/ //CLIENT_NAME/ip1testname/ip1testdir
    END_OF_LIST
    more
    cruft
    IP2_NAME
       /ip2name/ip2dir/ //CLIENT_NAME/ip2name/ip2dir
       /ip2testname/ip2testdir/ //CLIENT_NAME/ip2testname/ip2testdir
    END_OF_LIST
    Lore Ipsargh!
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-12
      • 2015-11-13
      • 2023-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多