ディレクトリツリーに次のタイムスタンプがあるとします。
root
|__ parent1
| |__ 2021
| | |__ 01
| | | |__ 22
| | | | |__ 12H
| | | | | |__ file1
| | | | | |__ file2
| | | | |__ 13H
| | | | | |__ file1
| | | | | |__ file2
| | | |__ 23
| | | | |__ 12H
| | | | | |__ file1
| | | | | |__ file2
| | | | |__ 13H
| | | | | |__ file1
| | | | | |__ file2
|__ parent2
| |__ etc
私が望むのは、このフォルダ構造を再帰的に進め、各フォルダなどにparent1
見つかったparent2
最新のタイムスタンプを含むファイルの数と一緒に表示することです。たとえば、次のようになります。
PARENT | LAST_TIMESTAMP | COUNT |
--------------------------------------------
parent1 | 2021-01-23T13:00:00 | 2 |
parent2 | 2022-01-01T00:00:00 | 5 | (dummy example)
... ... ...
他の答えも見てきましたが、すべてすべてのフォルダにあるファイルの変更日のみを考慮します。この場合は、フォルダ名にのみ関連します。
答え1
使用find
とperl
1行:
タブを使用してタイムスタンプとファイル名を区切り、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を使用している場合ファイル::検索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実行可能ファイルを使用してそれを保存し、chmod +x find-latest.pl
実行時に引数として1つ以上のディレクトリを指定します。
$ ./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 |
これはパールが必要です日付形式
基準寸法。 Debianではapt-get install libtimedate-perl
。cpan
strftime()
または、Perlに含まれるコアモジュールであるPOSIXモジュールの機能を使用することもできます。
File::Find
また、Perlに含まれるコアPerlモジュールです。
答え2
ディレクトリ階層の形式が次のとおりです。
cd root &&\
find . -type d ! -name . -path '*/*/*/*/*/*' |
sort -rt/ |
perl -sF/ -lane '$,=" | ";
print qw(PARENT LAST_TIMESTAMP KOUNT) if $.==1;
my $fc = -1+ split /\n/, qx(ls -l $_);
my $parent = $F[1];
!$seen{$parent}++ && do{
my($dt, $tm) = ("@F[2..4]", $F[5]);
my $timestamp = sprintf "%sT%s%s", $dt, $tm =~ s/H$//r, (":00" x 2);
print $parent, $timestamp, $fc;
};
' -- -\"=- -|column -t|
sed -e '1!b;h;s/./-/gp;x;G'
出力:-
----------------------------------------
PARENT | LAST_TIMESTAMP | KOUNT
----------------------------------------
pA | 2021-03-16T23:00:00 | 6
答え3
を使用すると、ワイルドカードパターンの修正タイムスタンプに基づいてソートされたディレクトリのzsh
一般的なファイルのリストを取得できます。$topdir
$topdir/**/*(.NDom)
ワイルドカード修飾子は、通常の(.NDom)
ファイル()の結果パス名のリストが.
変更タイムスタンプ()に基づいてソートされるようにします。修飾子のとはシェルオプションのとやや似たように動作しますが、この単一パターンの場合、Internet Explorerは隠された名前の一致を有効にしながらパターンがゼロの名前と一致することを許可します。o
m
N
D
nullglob
dotglob
bash
N
D
以下のスクリプトでは、次を使用します。
#!/bin/zsh
zmodload -F zsh/stat b:zstat
printf '| %-20s | %-20s | %5s |\n' PARENT LAST_TIMESTAMP COUNT
printf '| %-20s | %-20s | %5s |\n' '' '' '' | tr ' ' '-'
for topdir do
files=( $topdir/**/*(.NDom) )
if (( ${#files} > 0 )); then
timestamp=$( zstat -F '%Y-%m-%dT%H:%M:%S' +mtime $files[1] )
else
timestamp=N/A
fi
printf '| %-20s | %-20s | %5s |\n' $topdir $timestamp ${#files}
done
スクリプトは、zsh
コマンドラインで次のディレクトリパスセットを使用します。
$ ./script parent*/
...parent*/
トップレベルのディレクトリ名が一致する場所です。
単純なヘッダーを印刷してから、指定されたディレクトリパスを繰り返します。
各パスにワイルドカードパターンを使用して、最後に変更されたタイムスタンプに基づいてソートされた一般ファイル(隠し名前を含む)のパス名のリストを取得します$topdir/**/*(.NDom)
。
このリストが空でない場合zstat
(組み込みのロード可能なシェル)を使用して、最近変更されたファイルのタイムスタンプを抽出するか、N/A
ファイルが存在しない場合は文字列に設定します。
現在のディレクトリ、タイムスタンプ、およびファイルの数が表形式で印刷されます。
例を実行してください:
$ ./script ~me/{Documents,Work,admin}/
| PARENT | LAST_TIMESTAMP | COUNT |
|----------------------|----------------------|-------|
| /home/me/Documents/ | 2021-06-18T13:27:39 | 816 |
| /home/me/Work/ | 2021-06-22T10:57:49 | 2582 |
| /home/me/admin/ | 2021-07-14T11:13:30 | 191 |
ここで使用されるテーブル形式は有効なマークアップであり、例のテーブルは次のように表示されます。
親 | LAST_TIMESTAMP | 計算 |
---|---|---|
/ホーム/私/文書/ | 2021-06-18T13:27:39 | 816 |
/家/私/職場/ | 2021-06-22T10:57:49 | 2582 |
/家/私/管理者/ | 2021-07-14T11:13:30 | 191 |
bash
シェルでは、$topdir
次のように、ターゲットディレクトリの下にあるディレクトリ構造内で最近変更された一般的なファイルを見つけることができます。
shopt -s nullglob dotglob globstar
unset newest
for name in "$topdir"/**/*; do
if [ -f "$name" ] && [ ! -h "$name" ]; then
if [[ "$name" -nt "$newest" ]]; then
newest=$name
fi
fi
done
これは-nt
テストを使用してからbash
最後に変更されたファイルを追跡します$newest
。現在のファイルがシンボリックリンクではなく通常のファイルである場合、-f
否定テスト-h
はtrueです。
上記と同じですが、bash
シェル用に書かれています。
#!/bin/bash
shopt -s nullglob dotglob globstar
printf '| %-20s | %-20s | %5s |\n' PARENT LAST_TIMESTAMP COUNT
printf '| %-20s | %-20s | %5s |\n' '' '' '' | tr ' ' '-'
for topdir do
unset newest
count=0
for name in "$topdir"/**/*; do
# Test whether "$name" is a regular file
# and not a symbolic link.
if [ -f "$name" ] && [ ! -h "$name" ]; then
count=$(( count + 1 ))
if [[ "$name" -nt "$newest" ]]; then
newest=$name
fi
fi
done
if [ -n "$newest" ]; then
printf -v timestamp '%(%Y-%m-%dT%H:%M:%S)T' "$(stat -c %Y "$newest")"
else
timestamp=N/A
fi
printf '| %-20s | %-20s | %5s |\n' "$topdir" "$timestamp" "$count"
done
OpenBSD では以下を使用します。
timestamp=$( stat -f %Sm -t '%Y-%m-%dT%H:%M:%S' "$newest" )
変える
printf -v timestamp '%(%Y-%m-%dT%H:%M:%S)T' "$(stat -c %Y "$newest")"
このスクリプトでは(後者はLinux専用です)