2013-12-16 74 views
1

我需要做的是編寫一個腳本,它將讀取目錄列表 ,然後對它們進行排序,最後一個目錄將被「關閉」。在ASCII碼上按日期對PERL數組進行排序

my $ last_one = pop @sorted;

然後去年目錄將會被刪除 - 用系統(「RM-RF $ last_one)或 remove_tree($ last_one)

1 #!/usr/bin/perl 
2 use strict; 
3 use warnings; 
4 
5 my $dir_to_process = "/production/log/fo/archive/"; 
6 opendir DH, $dir_to_process or die "Sorry, this is not going to work out $!"; 
7 
8 while (my $name = readdir DH) { 
9  next if $name =~ /^\./; 
10  push(my @unsorted,$name) ; 
11  my @sorted_dir = sort @unsorted; 
12  foreach my $sorted (@sorted_dir) { 
13  print "$sorted\n"; 
14  sleep 1 ; 
15  } 
16 
17 } 

但是我有很多的麻煩分類目錄。 - 。它們是由這種格式寫 這是實際的輸出

2013Nov12 
2013Sep14 
2013Jul15 
2013Jan20 
2013Sep11 
2013May31 
2013Jul04 
2012Dec09 
2013Oct12 
2013Oct09 
2012Dec27 
2013Nov28 
2013Mar24 
2013Jun06 
2013Jun25 
+0

你在標題中說「通過ASCII排序」,但我假設你真正想要的是按日期排序(即最早到最新或反之亦然)? – ThisSuitIsBlackNot

+1

如果你只是想找到最古老的,排序是沒有意義的。 – ikegami

+0

問題是,它是按ascii排序,而不是按日期排序 - 是的,我需要的是最古老的日期目錄。 – capser

回答

2

排序()接受代碼塊,你可以定義自己的排序算法,只需將您的目錄名稱爲timestamp,你應該去這。將是卑鄙的像
sort { date2stamp($a) <=> date2stamp($b) } @unsorted
而內部date2stamp子使用POSIX :: mktime()創建日期字符串的正確的時間戳。

3

您需要一個函數將您的目錄名稱轉換爲日期(將日期信息拆分爲您可以排序的內容:年,月,日)。

下面是一個例子

sub parsedate { 
    my $name = shift; 
    my %months = ('Jan'=> 1, 'Feb' => 2, 'Mar' => 3, 'Apr' => 4, 
    'May'=> 5, 'Jun' => 6, 'Jul' => 7, 'Aug' => 8, 
    'Sep'=> 9, 'Oct' => 10, 'Nov' => 11, 'Dec' => 12); 

    my ($y,$m,$d); 
    $name =~ m/^(\d{4})(\w{3})(\d{2})$/ 
    and ($y,$m,$d) = ($1,$months{$2},$3) 
    or die "file name $name doesn't match"; 

    return sprintf("%04d%02d%02d",$y,$m,$d); 
} 

現在你可以使用你的新的子parsedate只是對它們進行排序。

my @sorted_dir = sort {parsedate($a) <=> parsedate($b)} @unsorted; 
2

轉化月份名稱爲數字,然後做了一些出來的年月日 的那麼數數字 的「使用Schwartzian變換」排序是用來將數字附加到文件名

#!/usr/bin/perl 
# 
# 
use warnings; 
use strict; 

my %monthval=qw(Jan 01 Feb 02 Mar 03 Apr 04 May 05 Jun 06 Jul 07 Aug 08 Sep 09 O 
ct 10 Nov 11 Dec 12); 


my @in=qw(2013Nov12 
2013Sep14 
2013Jul15 
2013Jan20 
2013Sep11 
2013May31 
2013Jul04 
2012Dec09 
2013Oct12 
2013Oct09 
2012Dec27 
2013Nov28 
2013Mar24 
2013Jun06 
2013Jun25); 

my @sorted = map{$_->[0]} sort { $a->[1] <=> $b->[1]} map { my ($y,$m,$d)=/(\d{ 
4})(\w{3})(\d{2})/; [$_,"$y".$monthval{$m}."$d"]} @in; 

foreach my $name (@sorted) { 
    print "$name\n"; 
} 
5

假設存在一個函數convert_date,它將日期轉換爲YYYYMMDD格式。如果你有一個,一個簡單的字符串比較會發現最古老的。

my ($oldest) = 
    sort { convert_date($a) cmp convert_date($b) } 
    @dirs; 

更快:

my ($oldest) = 
    map $_->[0], 
    sort { $a->[1] cmp $b->[1] } 
    map [ $_, convert_date($_) ], 
    @dirs; 

最快:

my ($oldest) = 
    map substr($_, 8), 
    sort 
    map convert_date($_) . $_, 
    @dirs; 

但是排序(O(N日誌N))是尋找一種元素(O的浪費方式(N ))。

my $oldest = $dirs[0]; 
for (@dirs) { 
    $oldest = $_ if convert_date($_) lt $oldest; 
} 

更快?

use List::Util qw(minstr); 
my $oldest = substr(minstr(map { convert_date($_) . $_ } @dirs), 8); 

現在,所有剩下的就是寫convert_date

use Carp qw(croak); 

my %month_num_by_en_name = (
    Jan => 1, Feb => 2, Mar => 3, Apr => 4, 
    May => 5, Jun => 6, Jul => 7, Aug => 8, 
    Sep => 9, Oct => 10, Nov => 11, Dec => 12, 
); 


sub convert_date { 
    my ($date) = @_; 

    my ($y,$m,$d) = $date =~ m/^(\d{4})(\w{3})(\d{2})\z/ 
     or croak("Invalid input"); 

    $m = $month_num_by_en_name{$m} 
     or croak("Invalid input"); 

    return sprintf("%04d%02d%02d", $y,$m,$d); 
} 

您也可以使用DateTime::Format::Strptime。這使得支持其他語言更容易。

use DateTime::Format::Strptime qw(); 

my $format = DateTime::Format::Strptime->new(
    pattern => '%Y%b%d', 
    locale => 'en_US', 
    on_error => 'croak', 
); 

sub convert_date { 
    my ($date) = @_; 
    return $format->parse_datetime($date)->strftime('%Y%m%d'); 
} 
+0

真棒解釋。你介意我問你爲什麼使用'鯉魚'?它是習慣性還是有收穫(總是談論OP的情景)? – foibs

+0

@foibs,因爲鯉魚提供'croak',這在這裏很合適。 – ikegami

+0

對不起,我不清楚。我的意思是'croak'比'die'更合適。謝謝 – foibs