2012-10-02 89 views
2

我將總行數作爲用戶輸入,然後從文件中刪除這些數字。如何刪除perl中文件的最後10行

我看到這個learn.perl.org/faq/perlfaq5.html#How-do-I-count-the-number-of-lines-in-a-file-然後我厭倦了下面的簡單邏輯。

邏輯:

  1. 獲取行的總數
  2. 由用戶
  3. 打印進入線

這裏的數字減去這是我的代碼:

#!/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;  
} 

那麼,我是不是在代碼中出現任何錯誤,也沒有任何輸出?爲什麼我只是不知道。

任何人都可以給我一些建議。

+0

你就不能看在反向文件?並刪除第n行? –

回答

12

一個Perl的解決方案是有效的大型文件,需要使用File::ReadBackwards

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 $!; 
  • 這不讀取整個文件的兩倍(與OP的方法)。
  • 這不會讀取整個文件(不像Tie::File解決方案)。
  • 這不會將整個文件讀入內存。
+0

+1這樣一個很好的解決方案,這是..偉大的:) –

+0

「這不讀取整個文件(不像Tie :: File解決方案)」=>我讀到「The Tie :: File解決方案是最有效的解決方案,至少對於大文件來說,因爲它不需要通讀整個文件來查找最後一行,也不會將整個文件讀入內存「,請參閱http://docstore.mik.ua/orelly/perl4 /cook/ch08_11.htm – Georg

+0

@Georg,Tie :: File很少是最有效的解決方案。充其量,它將幾乎像專門的解決方案一樣快,如File :: ReadBackwards,因爲它的所有開銷。但這不是這種情況。建議的解決方案使用'$#行',這必須導致整個文件被讀取。我希望1..10;'1..10;'或'delete($ lines [-1])的pop(@lines)與F :: RB解決方案几乎一樣快,但是我使用'strace'確認他們也讀取整個文件(儘管他們可以使用與F :: RB相同的方法)。 – ikegami

2

完成從在閱讀之後,你必須重新打開或seek IN, 0, 0重置其位置。您還必須將$.再次設置爲零。

而且最終狀態應改爲unless $. > $printed_line所以你跳過門檻的所有行。

+0

@ choroba。我嘗試使用seek功能,我的意思是我已經添加了seek(IN,0,0),並且使$。= 0;現在出來即將到來,但它並沒有刪除最後10行,我的意思是它正在打印整條線。 – Maverick

+0

@Maverick:查看更新。 – choroba

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; 
+0

POST編輯(變量$數字被遺忘​​) –

+0

_GLOBAL_文件句柄被_local_文件句柄替代,它更安全,這是一個最佳實踐。請參閱http://perldoc.perl.org/peropentut.html#Indirect-Filehandles –

+0

爲什麼選擇低估? –

1

剛看了反向文件並刪除前n行: -

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

注:這將加載整個文件到內存中。

+0

這也將文件向後打印出來。 – mob

+0

@mob ..你可以將你的打印語句移入其他的.. –

+0

所以。您仍然向後打印文件(最後10行除外)。 – mob

0
my $num_lines = 10; 
my $qfn  = 'file.txt'; 

system('head', '-n', -$num_lines, '--', $qfn); 
die "Error" if $?; 
6

另一種方法是使用Tie::File

#!/usr/bin/env perl 
use strict; 
use warnings; 
use Tie::File; 
tie my @lines, 'Tie::File', 'myfile' or die "$!\n"; 
$#lines -= 10; 
untie @lines; 

這有將文件加載到內存中,而行事像它的優勢。

+0

你打我一分鐘! –

+0

注意:這將讀取整個文件,併爲內存中的每一行創建一個索引。我的解決方案既不。 – ikegami

1

「更有趣」的答案:使用Tie::File

use strict; 
use warnings; 

use Tie::File; 
tie my @file, 'Tie::File', 'filename' or die "$!"; 

$#file -= 10; 
+0

注意:這會讀取整個文件,併爲內存中的每一行創建一個索引。我的解決方案既不。 – ikegami

1

你可以只緩衝區中的最後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, $_; 
    } 
} 

你也可以用File::Slurp::edit_file_lines做到這一點:

my @buffer; 
my $limit_reached = 0; 
edit_file_lines { 
    push @buffer, $_; 
    return ($limit_reached ||= @buffer > $num_lines_to_trim) ? shift @buffer 
     :              '' 
     ; 
} $name_of_file; 
4

這裏說的通的解決方案通過流和打印除最後的所有n行,其中n是命令行參數:

#!/usr/bin/perl 

my @cache; 
my $n = shift @ARGV; 

while(<>) { 
    push @cache, $_; 
    print shift @cache if @cache > $n; 
} 

或一個班輪版本:

perl -ne'BEGIN{[email protected]}[email protected],$_;print [email protected] [email protected]>$n' NUMBER 
+0

+1,這是最好的答案(除非需要就地編輯)。 – ikegami

0
# 
    # 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 
    # 
相關問題