如何在Perl中的文件顶部和底部添加行?

时间:2009-08-05 00:47:35

标签: perl filehandle

我想在文件的顶部和底部添加一行。我可以按照以下方式做到。

open (DATA, "</usr/old") || die "cant open old\n"; #file to which line has to be added

my @body=<DATA>;
close(DATA);

open (FILE, ">/usr/new") || die "cant open new\n"; #file after stuff has been added

print FILE "9   431";

print FILE "\n";

my $body=@body;

for (my $i=0; $i<$body;$i++){

    print FILE "$body[$i]";#not using for loop leads to addition of spaces in new file
}

print FILE "(3,((((1,4),(7,6)),(2,8)),5),9)";

由于我运行大量文件,因此这个过程非常耗时。 Perl是否具有用于在文件顶部和底部添加行的任何特定功能?

8 个答案:

答案 0 :(得分:10)

perlfaq5回答How do I change, delete, or insert a line in a file, or append to the beginning of a file?


如何更改,删除或插入文件中的行,或附加到文件的开头?

(由brian d foy提供)

从文本文件中插入,更改或删除行的基本思想包括读取和打印文件到要进行更改的位置,进行更改,然后读取和打印文件的其余部分。 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;

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

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 $_;
    }

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

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

您还可以使用Perl单行来就地修改文件。以下内容将inFile.txt中的所有'Fred'更改为'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 :(得分:2)

Perl无法在文件开头插入,因为很少有操作系统允许这样做。您需要重写此类型的重写操作。

该代码可能遇到的一个问题是您的地址空间无法容纳的真正大文件。

通过读取整个文件然后将其写出来,可能会遇到内存问题。我本来会做的是:

  • 重命名当前文件
  • 使用您想要在开头插入的内容重新创建
  • 将重命名的文件以大块(不一定是行)复制到新文件的末尾,
  • 在最后添加新位。

这将是快速且节省内存的。

当然,如果您的文件足够小以适应内存,请坚持使用您拥有的文件。这很好。

更新

足够的人似乎在误解我正在倡导一个我认为我会直接设置的shell脚本。您可以在本机Perl中执行上述所有操作。

但您可能想要考虑是否有必要使用Perl。 shell命令如:

( echo '9   431';cat /usr/old;echo '(3,((((1,4),(7,6)),(2,8)),5),9)' ) >/usr/new

也可以做到这一点(也可能同样快)。

当然,如果你需要 Perl,那么就把这个更新当作一个老人的乱骂: - )

答案 2 :(得分:2)

使用Tie::File,可以通过Perl数组访问磁盘文件的行。它带有标准发行版。

文档示例:

use Tie::File;

tie @array, 'Tie::File', filename or die ...;
$array[13] = 'blah';     # line 13 of the file is now 'blah'
print $array[42];        # display line 42 of the file

$n_recs = @array;        # how many records are in the file?
$#array -= 2;            # chop two records off the end

for (@array) {
    s/PERL/Perl/g;         # Replace PERL with Perl everywhere in the file
}

# These are just like regular push, pop, unshift, shift, and splice
# Except that they modify the file in the way you would expect
push @array, new recs...;
my $r1 = pop @array;
unshift @array, new recs...;
my $r2 = shift @array;
@old_recs = splice @array, 3, 7, new recs...;

untie @array;            # all finished

答案 3 :(得分:1)

已经给出了三个答案,这些答案延续了非常糟糕的做法:

open(FILE,"<file") or die "cannot open";

不仅如此,代码被破坏了,因为你没有打开文件进行写作而是阅读。

当打开失败时,您可以告诉用户为什么失败。请养成包含$的习惯!在错误消息中。另外,使用open的三个参数形式将模式与名称分开:

my $path="file";
open my($fh), '>', $path or die "$path: $!";

(这不能回答你的问题,但是我把它作为一个答案,而不是一个评论,以增加重点,以便我可以审查它,因为它是一个相当漫长的喷出。)

答案 4 :(得分:0)

你可以这样做

open(FILE,">", $file) or die "cannot open $file: $!";
print FILE "add line to top\n";
while (<FILE>) { print $_ ."\n";}
close(FILE);
print FILE "add line to bottom\n";

在命令行上

perl myscript.pl > newfile

答案 5 :(得分:0)

有许多方法可以做到这一点,例如使用简单的shell脚本,就像@Pax提到的那样。您还可以使用join()替换数组和循环:

open(DATA, "</usr/old") || die "cant open old\n"; #file to which line has to be added
my $body=join("", <DATA>);
open (FILE, ">/usr/new") || die "cant open new\n"; #file after stuff has been added
print FILE "9   431\n";
print(FILE $body);
print FILE "(3,((((1,4),(7,6)),(2,8)),5),9)";
close(FILE);

答案 6 :(得分:0)

我对ghostdog74的修改是文件句柄应该在print语句中,文件应该在第二个print语句后关闭。

    open(FILE, ">", "file") or die "cannot open $file: $!"; 
    print FILE "add line to top";
    while (<FILE>) { print $_;}
    print FILE "add line to bottom";
    close(FILE);

答案 7 :(得分:-1)

正如Pax所说,没有内置的方法可以做到这一点。但是如果你想用shell中的单行perl命令来实现它,你可以使用:

perl -ple 'print "Top line" if $. == 1; if (eof) { print "$_\nBottom line";  exit; }' yourfile.txt > newfile.txt