Bash

遞歸遍歷目錄並檢索最後一個時間戳文件

  • July 18, 2021

假設我有以下時間戳,如目錄樹:

root
 |__ parent1
 |      |__ 2021
 |      |     |__ 01
 |      |     |    |__ 22
 |      |     |    |    |__ 12H
 |      |     |    |    |    |__ file1
 |      |     |    |    |    |__ file2
 |      |     |    |    |__ 13H
 |      |     |    |    |    |__ file1
 |      |     |    |    |    |__ file2
 |      |     |    |__ 23
 |      |     |    |    |__ 12H
 |      |     |    |    |    |__ file1
 |      |     |    |    |    |__ file2
 |      |     |    |    |__ 13H
 |      |     |    |    |    |__ file1
 |      |     |    |    |    |__ file2
 |__ parent2
 |      |__ etc
                        

我想要的是遞歸地瀏覽這個文件夾結構,這樣,對於每個文件夾parent1parent2等,將顯示找到的最新時間戳,以及包含的文件數。例如,類似:

PARENT  |     LAST_TIMESTAMP    |  COUNT  |
--------------------------------------------
parent1  |  2021-01-23T13:00:00  |    2    |
parent2  |  2022-01-01T00:00:00  |    5    | (dummy example)
 ...             ...                ...

我已經看到了其他答案,但所有答案都只考慮了所有文件夾中文件的修改日期,而在這種情況下,它只與文件夾的名稱有關。

使用findperl單線:

這使用製表符來分隔時間戳和文件名,並使用 NUL 來分隔每條記錄 - 因此可以使用任何文件名,包括那些包含換行符的文件名。

find .. -type f -printf '%T@\t%p\0' | 
   perl -MDate::Format -0ne '
     ($t,$f) = split /\t/,$_,2;
     (undef,$p) = split "/", $f;

     $T{$p} = $t if ($t > $T{$p});
     $count{$p}++;

     END {
       my $fmt = "%-20s | %-19s | %5s |\n";
       printf "$fmt", "PARENT", "LAST_TIMESTAMP", "COUNT";
       print "-" x 52, "\n";

       foreach (sort keys %T) {
         printf $fmt, $_, time2str("%Y-%m-%dT%H:%M:%S",$T{$_}), $count{$_}
       }
     }'

它產生如下輸出:

PARENT               | LAST_TIMESTAMP      | COUNT | 
---------------------|---------------------|-------|
foo                  | 2021-07-16T22:54:22 |     4 | 
bar                  | 2021-06-29T12:25:06 |    13 | 
baz                  | 2021-07-14T14:31:43 |     5 | 
quux                 | 2021-07-16T19:46:21 |     7 | 

或者,如果您使用 perl 的File::Find模組,則不需要將find’ 的輸出通過管道傳輸到其中:

#!/usr/bin/perl

use strict;
use Date::Format;
use File::Find;

my %T;     # hash containing newest timestamp for each top-level dir
my %count; # count of files in each top-level dir

find(\&wanted, @ARGV);

my $fmt  = "| %-20s | %-19s | %5s |\n";
my $hfmt = "|-%-20s-|-%-19s-|-%5s-|\n";

#print "-" x 54, "\n";

printf "$fmt", "PARENT", "LAST_TIMESTAMP", "COUNT";
printf $hfmt, "-" x 20, "-" x 19, "-" x 5;

foreach (sort keys %T) {
 printf $fmt, $_, time2str("%Y-%m-%dT%H:%M:%S", $T{$_}), $count{$_}
}

#print "-" x 54, "\n";

sub wanted {
 return unless -f $File::Find::name;

 # uncomment only one of the following statements:

 # get the mod time of the file itself
 my $t = (stat($File::Find::name))[9];
 # get the mod time of the directory it's in
 #my $t = (stat($File::Find::dir))[9];

 my $p = $File::Find::dir;
 $p =~ s:^\.*/::;

 $T{$p} = $t if ($t > $T{$p});
 $count{$p}++;
};

將其另存為,例如find-latest.pl,make executable withchmod +x find-latest.pl並在執行時給它一個或多個目錄作為參數:

$ ./find-latest.pl ../
| PARENT               | LAST_TIMESTAMP      | COUNT |
|----------------------|---------------------|-------|
| foo                  | 2021-07-16T22:54:22 |     4 |
| bar                  | 2021-06-29T12:25:06 |    13 |
| baz                  | 2021-07-14T14:31:43 |     5 |
| quux                 | 2021-07-16T19:46:21 |     7 |

這需要 perl Date::Format 模組。在 debian 上,您可以使用apt-get install libtimedate-perl. 它也應該為其他發行版打包,否則使用cpan.

或者,您可以使用strftime()POSIX 模組中的函式,它是一個核心模組,包含在 perl 中。

File::Find也是 perl 的核心模組,包含在 perl 中。

引用自:https://unix.stackexchange.com/questions/658658