2012-02-17 41 views
0

我有幾個命令使用Perl將文本打印到文件。在這些print命令期間,我有一個if語句,它應該刪除我正在寫入的文件的最後5行,如果該語句爲真。行,可刪除的數量始終是5如何刪除文件的最後5行

if ($exists == 0) { 
    print(OUTPUT ???) # this should remove the last 5 lines 
} 
+0

退房這個問題:http://stackoverflow.com/questions/345513/how-can-i -delete-the-last-n-lines-of-a-file – asf107 2012-02-17 14:24:31

+1

從堆棧溢出和官方的Perl常見問題解答:[如何更改,刪除或插入文件中的行,或追加到文件的開頭在Perl?](http://stackoverflow.com/questions/2322140/how-do-i-change-delete-or-insert-a-line-in-a-file-or-append-to-the-beginning ) – daxim 2012-02-17 14:26:06

回答

4

您可以使用Tie::File

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

if ($exists == 0) { 
    $#array -= 5; 
} 

您可以使用打印時相同的陣列,而是使用push代替:

push @array, "line of text"; 
+0

只要我讀了標題,我就認爲「Tie :: File FTW!」你擊敗了我。 +1 – 2012-02-17 14:32:19

1

只有我能想到的明顯方式:

  1. 鎖定文件,scanbackwards找到一個位置並使用 truncate
  2. 不要直接打印到文件,請通過至少5行長的緩衝區 並修剪緩衝區。
  3. 打印表示「忽略最後五行」的標記。與緩衝區中讀取它們作爲#2

前 處理所有的文件全部是相當繁瑣的,但是這是平面文件恐怕性質。

HTH

+0

這並不是說這些「壞」建議,但Tie :: File具有內置的魔力。 – 2012-02-17 14:34:40

+0

@Joel Berger,不是沒有。 Tie :: File從頭開始讀取文件,所以它肯定比(1)對於大文件慢得多。更不要說它會在創建文件中每一行的索引時使用的所有內存。 – ikegami 2012-02-17 21:46:49

+0

@ikegami,你說得對#1更快(對於大文件)。所有我的意思是,Tie :: File將完成大部分工作,而不是它效率更高 – 2012-02-17 22:54:23

1

作爲替代,打印整個文件,除了最後5行:

open($fh, "<", $filename) or die "can't open $filename for reading: $!"; 
open($fh_new, ">", "$filename.new") or die "can't open $filename.new: $!"; 
my $index = 0; # So we can loop over the buffer 
my @buffer; 
my $counter = 0; 
while (<$fh>) { 
    if ($counter++ >= 5) { 
     print $fh_new $buffer[$index]; 
    } 
    $buffer[$index++] = $_; 
    $index = 0 if 5 == $index; 
} 
close $fh; 
close $fh_new; 
use File::Copy; 
move("$filename.new", $filename) or die "Can not copy $filename.new to $filename: $!"; 
+0

這是Richard Huxton的回答#2 – DVK 2012-02-17 14:53:07

+0

'$ index = 0 if if 5 == $ index'也可以是寫'$ index%= 5',假設增量爲1。 – TLP 2012-02-17 15:22:38

+1

這些是非常奇怪的公開電話。 'open'在成功時返回一個未定義的真值,在失敗時返回零 - 這兩者都不如文件句柄有用。 '$ file'是文件句柄應該在的地方,但它是未聲明的,並且你使用同一個變量兩次。 '$ filename.new'也需要雙引號或者不能編譯。 – Borodin 2012-02-17 15:25:15

3
$ tac file | perl -ne 'print unless 1 .. 5' | tac > file.tailchopped 
+1

我喜歡這個選擇,從來不知道'tac'之前... – Zaid 2012-02-17 19:12:53

+0

'head --lines = -5 file' – TLP 2012-02-17 20:50:34

+1

@TLP:'head:unknown option - -' and'usage:head [-count | -n計數] [文件...]'。這不是POSIX兼容的。 – tchrist 2012-02-17 20:57:44

1

File::ReadBackwards + truncate是最快的大型文件,並且很可能以最快的速度別的了短文件。

use File::ReadBackwards qw(); 

my $bfh = File::ReadBackwards->new($qfn) 
    or die("Can't read \"$qfn\": $!\n"); 

$bfh->readline() or last for 1..5; 

my $fh = $bfh->get_handle(); 
truncate($qfn, tell($fh)) 
    or die $!; 

Tie :: File是最慢的,並且使用大量的內存。避免這種解決方案。

+0

經過測試和修復。 – ikegami 2012-02-17 22:04:10

0

你可以嘗試這樣的事:

open FILE, "<", 'filename'; 
if ($exists == 0){ 
@lines = <FILE>; 
$newLastLine = $#lines - 5; 
@print = @lines[0 .. $newLastLine]; 
print "@print"; 
} 

甚至縮短:

open FILE, "<", 'filename'; 
@lines = <FILE>; 
if ($exists == 0){ 
print "@lines[0 .. $#lines-5]"; 
} 
相關問題