2012-06-13 139 views
0

在此代碼中,我解析了一個文件(包含來自ls -lrt的輸出)以獲取日誌文件的修改日期。然後,我將所有日誌文件移動到一個新的文件夾中,修改日期已添加到文件名中,並將所有這些文件都設置爲tar。perl while循環

我得到的問題是在while循環中。因爲它正在讀取while循環持續運行15次的所有文件的數據。我知道代碼中存在一些問題,但我無法弄清楚。

在while循環中我分裂了ls -lrt記錄來查找日誌文件修改日期。 $file是我存儲在文本文件/scripts/yagya.txt中的ls命令的輸出,以獲取修改日期。但while循環正在執行15次,因爲文件夾中有15個與該模式匹配的日誌文件。

#!/usr/bin/perl 
use File::Find; 
use strict; 

my @field; 
my $filenew; 
my $date; 
my $file = `ls -lrt /scripts/*log*`; 
my $directory="/scripts/*.log"; 
my $current = localtime; 
my $current_time = $current; 
$current_time = s/\s+//g; 
my $freetime = $current_time; 
my $daytime = substr($current_time,0,8); 
my $seconddir = "/$freetime/"; 

system ("mkdir $seconddir"); 

open (MYFILE,">/scripts/yagya.txt"); 
print MYFILE "$file"; 
close (MYFILE); 

my $data = "/scripts/yagya.txt"; 
my $datas = "/scripts/"; 
my %options = (
    wanted => \&wanted, 
    untaint => 1 
); 

find (\%options, $datas); 
sub wanted { 
    if (/[._]log\d*$/){ 
     my $files; 
     my @fields; 
     my $fields; 
     chomp; 
     $files=$_; 

     open (MYFILE,$data); 
     while(<MYFILE>){ 
      chop; 
      s/#.*//; 
      next unless /\S/; 
      @fields = (split)[5,6,7]; 
      $fields = join('',@fields), "\n"; 
     } 
     close (MYFILE); 

     system ("mv $files $seconddir$fields$files"); 
    } 
} 

system ("tar cvf /$daytime/$daytime.tar.gz /$daytime/*log*"); 
system ("rm $seconddir*log*"); 

system ("rm $data"); 
+3

請學習如何縮進代碼。 – Alnitak

+3

請以某人可以理解的方式重新陳述您的問題。 –

+3

嘗試用以下方法重新構造問題:1.)我有這個2.)我想得到這個3.)我試過(已經在這裏)。看來,你正在嘗試將shell腳本重寫爲perl,6次調用system(...),比如system(「rm $ data」)而不是'unlink $ data或警告「無法取消鏈接$ data:$!」。 ;'。你可以發佈shell腳本,如果你有嗎? – jm666

回答

3

您的代碼非常難以閱讀。看起來你已經在開始測試之前將程序編寫成一個大塊。這種工作方式很常見,但非常錯誤。您應該首先實施一小部分程序,並在添加更多功能之前進行測試,再次測試等等。這樣你就不會被大量未經測試的程序一次性解決許多問題所困擾。

如果您在程序頂部將use warnings添加到您的use strict中,它也會對您有所幫助。它有助於捕捉您可能會忽略的簡單錯誤。

此外,您是否知道File::Find每次遇到文件時都會調用您的wanted回調子例程?它不會一次傳遞所有文件。

問題似乎是,您正在通過yagya.txt文件一直讀取文件,當您找到與File::Find找到的當前文件相匹配的記錄時應該停止。您需要做的是檢查ls輸出中的當前記錄是否以當前文件的名稱結尾。如果你寫這樣的

while (<MYFILE>) { 
    if (/\Q$files\E$/) { 
    my @fields = (split)[5,6,7]; 
    $fields = join('',@fields); 
    last; 
    } 
} 

循環再$fields將結束與當前文件的修改日期,這是你想要的。

但是如果您使用Perl爲您讀取文件修改日期,這將會容易上千倍。

而不是寫一個ls上市文件並讀的,你應該做這樣的事情

use File::stat; 

my $mtime = localtime(stat($files)->mtime); 

,這將給你喜歡Wed Jun 13 11:25:23 2012的字符串。我的ls輸出中的日期僅包括月份名稱,月份的日期和時間,如Jun 8 12:37。這是不是很具體,你或許應該至少包括一年的時間,但產生從這個$mtime相同的字符串,你可以寫

my $fields = join '', (split ' ', $mtime)[1,2,3]; 

有很多我可以說你的計劃,但我希望這會讓你現在得到它。


的事情另外一對夫婦,我注意到:

  • $current_time = s/\s+//g應該$current_time =~ s/\s+//g從當前時間字符串

  • Sun Jun 3 11:50:54 2012值將減少至刪除所有空格SunJun311:53:552012$daytime將取值SunJun31這是不正確的

+0

和'ls -ltr'爲舊文件將顯示年份而不是時間,如「5 Aug 2001」,而不是「5 Aug 11:34」... – jm666

1

我通常不建議使用bash,而不是perl的,但有時要短得多

這個問題有兩個部分:

  1. 重命名文件到另一個目錄,並添加時間戳到文件名
  2. 存檔他們每隔幾分鐘或幾小時,幾天...等。

爲1)

find ./scripts -name \*[_.]log\* -type f -printf "%p\0./logs/%TY%Tm%Td-%TH%Tk%TM-%f\0" | xargs -0 -L 2 mv 

上面會發現[_]登錄他們的名字的所有純文本文件,並將其重命名爲./logs目錄時間戳前綴。例如

./scripts/aaa.log12 get renamed into ./logs/20120403-102233-aaa.log12 

2)歸檔

ls logs | sed 's/\(........-....\).*/\1/' | sort -u | while read groupby 
do 
    (cd logs && echo tar cvzf ../$groupby.tgz $groupby*) 
done 

這將通過時間戳的前綴創建tar歸檔。 (假設./logs只包含具有有效(時間戳)文件名的文件)

當然,上面的sed模式不好,但清楚地顯示從時間戳中刪除seconds - 因此它正在創建歸檔分鐘。如果想要另一個分組,您可以使用:

sed 's/\(........-..\).*/\1/' - by hours 
sed 's/\(........\).*/\1/' - by days 

其他:

  • -printf對找到的是僅支持查找的GNU版本 - 常見於Linux的
  • 通常不是一個好的做法直接合作在「/」,像/scripts,因此我的示例使用./
  • 如果您./scrips子樹存在相同的時間戳相同的文件名時,MV將覆蓋第一,如具有相同時間戳的./scripts/a/a.log和./scripts/x/a.log都將重命名爲./logs/TIMESTAMP-a.log