如何在perl中删除文件的最后10行

如何在perl中删除文件的最后10行,perl,Perl,我将总行数作为用户输入,然后从文件中删除这些行数 我看到这个learn.perl.org/faq/perlfaq5.html#How-do-I-count-the-number-of-line-in-a-file-然后我厌倦了下面的简单逻辑 逻辑: 获取行的总数 减去用户输入的数字 打印行 这是我的代码: #!/usr/bin/perl -w use strict; open IN, "<", "Delete_line.txt" or die " Can not open the

我将总行数作为用户输入,然后从文件中删除这些行数

我看到这个learn.perl.org/faq/perlfaq5.html#How-do-I-count-the-number-of-line-in-a-file-然后我厌倦了下面的简单逻辑

逻辑:

  • 获取行的总数
  • 减去用户输入的数字
  • 打印行
  • 这是我的代码:

    #!/usr/bin/perl -w
    use strict;
    
    open IN, "<", "Delete_line.txt"
        or die " Can not open the file $!";
    open OUT, ">", "Update_delete_line.txt" 
        or die "Can not write in the file $!";
    
    my ($total_line, $line, $number, $printed_line);
    
    print"Enter the number of line to be delete\n";
    $number = <STDIN>;
    
    while ($line = <IN>) {
    
        $total_line = $.;  # Total number of line in the file
    }
    
    $printed_line = $total_line - $number;
    
    while ($line = <IN>) {
    
        print OUT $line unless $.== $printed_line;      
    }
    
    #/usr/bin/perl-w
    严格使用;
    在“,”更新\删除\行.txt”中打开
    或死“无法写入文件$!”;
    我的($total\u line,$line,$number,$printed\u line);
    打印“输入要删除的行数\n”;
    $number=;
    而($line=){
    $total_line=$。;#文件中的行总数
    }
    $printed_line=$total_line-$number;
    而($line=){
    打印出$行,除非$.==$打印行;
    }
    
    嗯,我既没有收到任何代码错误,也没有收到任何输出?为什么我不知道


    谁能给我一些建议吗

    从中读取完毕后,您必须重新打开它或
    在0,0中搜索以重置其位置。您还必须将
    $。
    再次设置为零


    此外,除非$。>$打印了_行
    ,因此您跳过了阈值以上的所有行。

    使用类似C的
    for
    :

    #!/usr/bin/perl -w
    use strict;
    
    open(my $in,"<","Delete_line.txt") or die "Can not open the file $!";
    open(my $out,">","Update_delete_line.txt") or die"Can not write in the file $!";
    
    print"Enter the number of lines to be delete\n";
    my $number=<STDIN>;
    
    my @file = <$in>;
    
    for (my $i = 0; $i < $#file - $number + 1; $i++) {
        print $out $file[$i];
    }
    
    close $in;
    close $out;
    
    #/usr/bin/perl-w
    严格使用;
    打开(my$in,“,”Update_delete_line.txt“)或死“无法写入文件$!”;
    打印“输入要删除的行数\n”;
    我的$number=;
    my@file=;
    对于(我的$i=0;$i<$#文件-$number+1;$i++){
    打印$out$file[$i];
    }
    以美元收盘;
    收尾美元;
    
    只需反向读取文件并删除前n行:-

    open my $filehandle, "<", "info.txt";
    my @file = <$filehandle>;
    splice(@file, -10);
    print @file;
    

    打开我的$filehandle,”另一种方法是使用

    这样做的好处是,不会像加载文件一样将文件加载到内存中。

    更有趣的答案是:使用


    对于大型文件高效的Perl解决方案需要使用


    • 这不会读取整个文件两次(与OP的方法不同)

    • 这不会读取整个文件(与解决方案不同)

    • 这不会将整个文件读入内存

    您可以缓冲最后10行,然后不打印剩余的10行

    use English qw<$INPLACE_EDIT>;
    
    {   local @ARGV         = $name_of_file_to_edit;
        local $INPLACE_EDIT = '.bak';
        my @buffer;
        for ( 1..$num_lines_to_trim ) { 
            push @buffer, <>;
        }
    
        while ( <> ) { 
            print shift @buffer;
            push @buffer, $_;
        }
    }
    

    这里是一个通过流并打印除最后n行以外的所有行的解决方案,其中n是命令行参数:

    #!/usr/bin/perl
    
    my @cache;
    my $n = shift @ARGV;
    
    while(<>) {
        push @cache, $_;
        print shift @cache if @cache > $n;
    }
    
    #
    #读取文件修剪通过的行数的顶部和底部
    #然后返回字符串
    #被盗自:http://stackoverflow.com/a/9330343/65706
    #用法:
    #my$StrCatFile=$objFileHandler->ReadFileReturnTrimmedStrAtTopBottom(
    #$FileToCat、$numorwstoremoveattop、$numorwstoremoveattown);
    子读取文件返回TrimmedStratTopBottom{
    我的$self=shift;
    我的$file=shift;
    我的$NumOfLinesToRemoveAtTop=shift;
    我的$NumOfLinesToRemoveAtBottom=shift;
    我的@cache;
    我的$StrTmp=();
    我的$StrReturn=();
    我的$fh=();
    
    open($fh,“难道你不能反向读取文件吗?”并删除前n行吗?全局文件句柄被本地文件句柄取代,这更安全&这是一种最佳做法。请参阅,这也会向后打印文件。因此,你仍然在向后打印文件(最后10行除外)@mob..O.O..Nice catch mob..那么这可能只用于删除行..@choroba.我尝试了seek函数,我的意思是我添加了seek(IN,0,0)我将$.=0;现在输出即将到来,但它没有删除最后10行,我的意思是它正在按原样打印整行。注意:这将读取整个文件,并为内存中的每一行创建索引。我的解决方案两者都没有。注意:这将读取整个文件,并为内存中的每一行创建索引。我的解决方案两者都没有。+1,这是最好的回答(除非需要就地编辑)。“这不会读取整个文件(与Tie::file solutions不同)”=>我读到“Tie::file solutions是最有效的解决方案,至少对于大型文件而言,因为它不必读取整个文件以找到最后一行,也不会将整个文件读入内存”,请参阅@Georg,Tie::File很少是最有效的解决方案。由于其所有开销,它最多只能与专用解决方案(如File::ReadBackwards)一样快。但这里不是这样。建议的解决方案使用
    $#行
    ,这必然会导致读取整个文件。我希望
    弹出(@lines)对于1..10;
    删除($lines[-1]),对于1..10;
    的速度几乎与F::RB解决方案一样快,但我使用
    strace
    确认他们也读取了整个文件(即使他们可以使用与F::RB相同的方法)@Georg,这还不算内存使用率。Tie::File保存了它遇到的每一行的位置索引。
    delete($lines[-1])
    在一个包含64字节行的8MiB文件上,导致Tie::File为这些偏移量使用了刚刚超过4MiB的内存!!!(它们不属于可以控制大小的缓存和缓冲区。)@Georg,链接的文档是完全错误的。Tie::File与前面的代码段做的事情完全相同,但有很多额外的CPU和内存开销。@Georg,Gah,如果您的平均行很短(例如,与源代码一样),那么Tie::File实际上可以为其偏移量使用比整个文件更多的内存!!!
    use strict;
    use warnings;
    
    use Tie::File;
    tie my @file, 'Tie::File', 'filename' or die "$!";
    
    $#file -= 10;
    
    use File::ReadBackwards qw( );
    
    my $num_lines = 10;
    my $qfn = 'file.txt';
    
    my $pos = do {
       my $fh = File::ReadBackwards->new($qfn)
          or die $!;
       $fh->readline() for 1..$num_lines;
       $fh->tell()
    };
    
    truncate($qfn, $pos)
       or die $!;
    
    use English qw<$INPLACE_EDIT>;
    
    {   local @ARGV         = $name_of_file_to_edit;
        local $INPLACE_EDIT = '.bak';
        my @buffer;
        for ( 1..$num_lines_to_trim ) { 
            push @buffer, <>;
        }
    
        while ( <> ) { 
            print shift @buffer;
            push @buffer, $_;
        }
    }
    
    my @buffer;
    my $limit_reached = 0;
    edit_file_lines {  
        push @buffer, $_;
        return ( $limit_reached ||= @buffer > $num_lines_to_trim ) ? shift @buffer
             :                                                       ''
             ;
    } $name_of_file;
    
    #!/usr/bin/perl
    
    my @cache;
    my $n = shift @ARGV;
    
    while(<>) {
        push @cache, $_;
        print shift @cache if @cache > $n;
    }
    
    perl -ne'BEGIN{$n=shift@ARGV}push@c,$_;print shift@c if@c>$n' NUMBER
    
      #
      # Reads a file trims the top and the bottom of by passed num of lines
      # and return the string 
      # stolen from : http://stackoverflow.com/a/9330343/65706
      # usage :       
      # my $StrCatFile = $objFileHandler->ReadFileReturnTrimmedStrAtTopBottom ( 
      #       $FileToCat , $NumOfRowsToRemoveAtTop , $NumOfRowsToRemoveAtBottom) ; 
      sub ReadFileReturnTrimmedStrAtTopBottom {
    
         my $self = shift ; 
         my $file = shift ; 
         my $NumOfLinesToRemoveAtTop = shift ; 
         my $NumOfLinesToRemoveAtBottom = shift ; 
    
         my @cache ; 
         my $StrTmp = () ; 
         my $StrReturn = () ; 
         my $fh = () ; 
    
         open($fh, "<", "$file") or cluck (   "can't open file : $file for reading: $!" ) ;
         my $counter = 0;
         while (<$fh>) {
             if ($. >= $NumOfLinesToRemoveAtTop + 1) {
                 $StrTmp .= $_ ;
             }
         } 
         close $fh;
    
         my $sh = () ; 
         open( $sh, "<", \$StrTmp) or cluck(   "can't open string : $StrTmp for reading: $!" ) ;
         while(<$sh>) {
             push ( @cache, $_  ) ;
             $StrReturn .= shift @cache if @cache > $NumOfLinesToRemoveAtBottom;
         }
         close $sh ; 
         return $StrReturn ; 
      } 
      #eof ReadFileReturnTrimmedStrAtTopBottom
      #