Perl编辑文件

时间:2011-02-03 17:55:22

标签: perl file

我正在尝试打开文件,在文件中搜索特定字符串以开始搜索,然后在文件中对字符串执行替换。例如,我的文件如下:

  

测试旧

     

Hello World

     

     

数据

     

Begin_search_here

     

新数据

     

旧数据

     

新数据

我想打开文件,从“Begin_search_here”开始搜索,然后用“New”替换单词“Old”的下一个实例。我的代码如下所示,我正确地找到了字符串,但由于某种原因,我没有写在正确的位置。

open(FILE, "+<$filename") || die "problem opening file";

my search = 0;
while(my $line = <FILE>)
{
if($line =~ m/Begin_search_here/)
{
$search = 1;
}

if($search == 1 && $line =~m/Old/)
{
$line = s/Old/New/;
print FILE $line
}

close FILE;

6 个答案:

答案 0 :(得分:4)

这里你去:

local $^I = '.bak';
local @ARGV = ($filename);
local $_;
my $replaced = 0;

while (<>) {
    if (!$replaced && /Begin_search_here/ .. $replaced) {
        $replaced = s/Old/New/;
    }
    print;
}

说明:

设置$^I变量可以进行就地编辑,就像使用-i标志运行perl一样。原始文件将以与原始文件相同的名称保存,但扩展名为“.bak”;如果您不想进行备份,请将".bak"替换为""

@ARGV设置为要进行就地编辑的文件列表;这里只是您在变量$filename中命名的单个文件。

$_已本地化,以防止在子代码中出现此代码段时覆盖此常用变量。

触发器操作符..用于确定要执行替换的文件的哪个部分。在第一次遇到匹配模式Begin_search_here的行时,它将为false,并且然后将保持为真,直到第一次发生替换(如变量$replaced中所记录的那样),它将关闭。

答案 1 :(得分:1)

您滥用随机访问文件模式。当您更新$line并说print FILE $line时,文件句柄的“光标”已经位于 next 行的开头。因此,原始行不会更改,下一行会被覆盖,而不是覆盖原始行。

现场编辑(请参阅perlrun)看起来非常适合此问题。

否则,您需要阅读tell函数以在读取行之前保存文件位置,并在重写行之前将seek返回到该位置。哦,你写的数据必须与你覆盖的数据大小完全相同,否则你将完全满足你的文件 - 见this question

答案 2 :(得分:1)

通过以读取模式(open( my $fh, '<', $file ) or die ...;)打开输入文件,并将修改后的文本写入临时输出文件,然后在输入文件的顶部复制临时文件时,最好能得到满意的服务完成你的处理。

答案 3 :(得分:1)

我做了很多像这样的编辑,我提出了一个通用的(但是精简的)策略:

use strict;
use warnings;

use English qw<$INPLACE_EDIT>;
use Params::Util qw<_CODE>;

local $INPLACE_EDIT = '.bak';
local @ARGV = '/path/to/file';

my @line_actions 
    = ( qr/^Begin_search_here/
      , qr/^Old Data/ => sub { s/^Old/New/ }
      ); 
my $match = shift @line_actions;
while ( <> ) { 
    if ( $match and /$match/ ) { 
        if ( _CODE( $line_actions[0] )) { 
            shift( @line_actions )->( $_ );
        }
        $match = shift @line_actions;
    }
    print;
}

答案 4 :(得分:0)

这很有效。正如您所指定的那样,它只会替换一次。

#! /usr/bin/perl -pi.bak

if (not $match_state) {
  if (/Begin_search_here/) {
    $match_state = "accepting";
  }
}
elsif ($match_state eq "accepting") {
  if (s/Old/New/) {
    $match_state = "done";
  }
}

答案 5 :(得分:0)

在编辑文件时要非常小心。如果您要替换的数据长度不同,则会破坏该文件。此外,如果你的程序在中间失败,你最终会得到一个被破坏的文件。

您最好的选择是读取每一行,处理该行,并将每行写入新文件。这甚至允许您运行程序,检查输出,如果有错误,请修复它并重新运行程序。然后,一旦一切正常,请添加步骤以将新文件移动到旧名称。

我从版本3.x开始一直在使用Perl,我想不出有一次我修改了文件

use strict;
use warnings;

open (INPUT, "$oldfile") or die qq(Can't open file "$oldFile" for reading);
open (OUTPUT, "$oldfile.$$") or die qq(Can't open file "$oldfile.$$" for writing);

my $startFlag = 0;
while (my $line = <INPUT>) {
    if ($line ~= /Begin_search_here/) {
        $startFlag = 1;
    }
    if ($startFlag) {
        $line =~ s/New/Old/;
    }
    print OUTPUT "$line";
}

# 
# Only implement these two steps once you've tested your program
#
unlink $oldfile;
rename $oldfile.$$", $oldfile;