如何用Perl替换文件中间的行?

时间:2010-02-17 05:29:32

标签: perl file text replace append

我在追加模式下打开文件。我需要替换文件中的第2,3和4行,稍后我需要在文件末尾添加新数据。

5 个答案:

答案 0 :(得分:40)

我认为这是我最常转发到Stackoverflow的常见问题解答。 perlfaq5How do I change, delete, or insert a line in a file, or append to the beginning of a file?的答案。

忘记追加模式的东西。这只会让你的生活更加艰难。


从文本文件中插入,更改或删除行的基本思想包括读取和打印文件到要进行更改的位置,进行更改,然后读取和打印文件的其余部分。 Perl不提供对行的随机访问(特别是因为记录输入分隔符$/是可变的),尽管Tie::File之类的模块可以伪造它。

执行这些任务的Perl程序采用打开文件,打印行,然后关闭文件的基本形式:

open my $in,  '<',  $file      or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";

while( <$in> )
    {
    print $out $_;
    }

close $out;

在该基本表单中,添加您需要插入,更改或删除行的部分。

要将行添加到开头,请在进入打印现有行的循环之前打印这些行。

open my $in,  '<',  $file      or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";

print $out "# Add this line to the top\n"; # <--- HERE'S THE MAGIC

while( <$in> )
    {
    print $out $_;
    }

close $out;

要更改现有行,请插入代码以修改while循环内的行。在这种情况下,代码找到所有小写版本的“perl”并将它们大写。每一行都会发生这种情况,所以请确保你应该在每一行都这样做!

open my $in,  '<',  $file      or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";

print $out "# Add this line to the top\n";

while( <$in> )
    {
    s/\b(perl)\b/Perl/g;
    print $out $_;
    }

close $out;

要仅更改特定行the input line number, $.,这非常有用。首先阅读并打印到您想要更改的行。接下来,阅读您要更改的单行,更改并打印它。之后,阅读其余部分并打印出来:

while( <$in> )   # print the lines before the change
    {
    print $out $_;
    last if $. == 4; # line number before change
    }

my $line = <$in>;
$line =~ s/\b(perl)\b/Perl/g;
print $out $line;

while( <$in> )   # print the rest of the lines
    {
    print $out $_;
    }

要跳过行,请使用循环控件。此示例中的下一个会跳过注释行,最后一个会在遇到__END____DATA__时停止所有处理。

while( <$in> )
    {
    next if /^\s+#/;             # skip comment lines
    last if /^__(END|DATA)__$/;  # stop at end of code marker
    print $out $_;
    }

通过使用next来跳过您不想在输出中显示的行来删除特定行。此示例每隔五行跳过一次:

while( <$in> )
    {
    next unless $. % 5;
    print $out $_;
    }

如果由于一些奇怪的原因,你真的想要一次看到整个文件而不是逐行处理,你可以把它捏进去(只要你能把整个文件放在内存中!):< / p>

open my $in,  '<',  $file      or die "Can't read old file: $!"
open my $out, '>', "$file.new" or die "Can't write new file: $!";

my @lines = do { local $/; <$in> }; # slurp!

    # do your magic here

print $out @lines;

File::SlurpTie::File等模块也可以提供帮助。但是,如果可以,请避免立即读取整个文件。在进程完成之前,Perl不会将该内存返回给操作系统。

您还可以使用Perl单行来就地修改文件。以下内容将所有'Fred'更改为 inFile.txt 中的'Barney',并使用新内容覆盖文件。使用-p开关,Perl围绕您使用-e指定的代码包裹一个while循环,-i启用就地编辑。当前行位于$_。使用-p,Perl会在循环结束时自动打印$_的值。有关详细信息,请参阅perlrun

perl -pi -e 's/Fred/Barney/' inFile.txt

要备份inFile.txt,请为-i添加一个文件扩展名:

perl -pi.bak -e 's/Fred/Barney/' inFile.txt

要仅更改第五行,您可以添加测试检查$.,即输入行号,然后仅在测试通过时执行操作:

perl -pi -e 's/Fred/Barney/ if $. == 5' inFile.txt

要在某一行之前添加行,您可以在Perl打印$_之前添加一行(或多行!):

perl -pi -e 'print "Put before third line\n" if $. == 3' inFile.txt

您甚至可以在文件的开头添加一行,因为当前行在循环结束时打印:

perl -pi -e 'print "Put before first line\n" if $. == 1' inFile.txt

要在文件中已有的行之后插入一行,请使用-n开关。它就像-p,只是它在循环结束时不打印$_,所以你必须自己做。在这种情况下,首先打印$_,然后打印要添加的行。

perl -ni -e 'print; print "Put after fifth line\n" if $. == 5' inFile.txt

要删除行,只打印您想要的行。

perl -ni -e 'print unless /d/' inFile.txt

    ... or ...

perl -pi -e 'next unless /d/' inFile.txt

答案 1 :(得分:4)

您可以使用Tie::File执行此操作。 (请注意,为了替换初始行,必须重写整个文件,但Tie :: File会隐藏您的详细信息。)

答案 2 :(得分:3)

一个好的Perl习语是读写标准输入和输出。您可以根据需要进行管道和重定向。通过运算符<>(readline的换行),Perl将打开您在命令行中作为参数传递的文件。

回答你的问题,几行代码(尽可能干净):

#!/usr/bin/env perl
use strict; use warnings;

while (<>) {
  if ($. == 2) {
    print "new data", "\n";
    next;
  }
  if ($. == 3) {
    print "very new data", "\n";
    next;
  }
  print;
}

print "more data", "\n"; 

然后以这种方式调用它:perl yourscript.pl inputfile&gt; OUTPUTFILE

如果您想自己打开文件(这里我们只是跳过不需要的行):

my open $in_fh, '<', $inputfile
  or die "Can't open file $inputfile: $!";

my open $out_fh, '>', $outputfile
  or die "Can't open file $output: $!";

while (my $line = <$in_fh>) {
  next if ( $. == 2 or $. == 3 or $. == 4 );
  print $out_fh $line;
}
print $out_fh "...whatever\n";

答案 3 :(得分:0)

如果您在追加模式中打开文件,那么当您打开文件时,您无法替换文件中已有的行。附加文件意味着您的程序只能读取文件并添加到文件末尾。

您可以创建一个新文件,向其中添加内容(可能基于来自不同文件的内容),然后将新文件复制到不同的文件中。

我想我不太明白这项任务。

答案 4 :(得分:-3)

use File::Copy;

        copy("/file1.txt","/file1_old.txt");
        open(FILEHANDLE,">file1.txt");
        open(FILEHANDLE1,"<file1_old.txt");

        my $linecount=1;
        while(<FILEHANDLE1>)
        {
            print $_."\n";

            if($linecount>4)
            {
                print FILEHANDLE "$_";
            }
            $linecount++;
        }

        {
                ## new data will be placed
        }
        #####close the file handle
         close(FILEHANDLE1);
         close(FILEHANDLE);