ディレクトリツリーで最も古いファイルを見つけるためのシェルワンライナーを探しています。
これは機能します(Daniel Anderssonの提案を取り入れるために更新されました):
find -type f -printf '%T+ %p\n' | sort | head -n 1
これはもう少し移植性が高く、GNU find
拡張子-printf
に依存しないため、BSD/OS Xでも同様に機能します。
find . -type f -print0 | xargs -0 ls -ltr | head -n 1
ここでの唯一の欠点は、それがARG_MAX
のサイズにいくぶん制限されているということです(はほとんどの新しいカーネルには関係ないはずです)。したがって、返されるgetconf ARG_MAX
文字(私のシステムでは262,144)を超える文字がある場合、それはあなたに正しい結果を与えません。 -print0
とxargs -0
はそうではないので、それはPOSIXにも準拠していません。
この問題に対するより多くの解決策がここに概説されています: ディレクトリ内で最新の(最新、最古、最古)ファイルを見つけるにはどうすればいいですか? - Greg's Wiki
以下のコマンドは、あらゆる種類の奇妙なファイル名で動作することが保証されています。
find -type f -printf "%T+ %p\0" | sort -z | grep -zom 1 ".*" | cat
find -type f -printf "%T@ %T+ %p\0" | \
sort -nz | grep -zom 1 ".*" | sed 's/[^ ]* //'
stat -c "%y %n" "$(find -type f -printf "%T@ %p\0" | \
sort -nz | grep -zom 1 ".*" | sed 's/[^ ]* //')"
改行文字(\0
)の代わりにNULLバイト(\n
)を使用すると、ファイル名の1つに改行文字が含まれている場合でもfindの出力が理解できるようになります。
-z
スイッチを使用すると、sortとgrepの両方でNULLバイトのみが行末文字として解釈されます。 headのようなスイッチはないので、代わりにgrep -m 1
を使います(1回のみ)。
コマンドは実行時間順に並べられています(私のマシンで測定)。
最初のコマンドはすべてのファイルのmtimeを最初に人間が読める形式に変換してからそれらの文字列をソートする必要があるため、最も遅くなります。猫への配管は出力の着色を避けます。
2番目のコマンドは少し速いです。それはまだ日付変換を実行しますが、Unix Epochから経過した秒数を数値的にソート(sort -n
)することはもう少し早くなります。 sedはUnix Epochからの秒数を削除します。
最後のコマンドはまったく変換を行わず、最初の2つのコマンドよりもかなり速くなるはずです。 findコマンド自体は最も古いファイルのmtimeを表示しないので、statが必要です。
ここで受け入れられている答えや他の人が仕事をしていますが、あなたが非常に大きな木を持っていれば、それらすべてがファイルの束全体をソートするでしょう。
並べ替える必要なしに、それらをリストして最も古いものを追跡することができればもっと良いでしょう。
私がこの代替ソリューションを思いついたのは、その理由です。
ls -lRU $PWD/* | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { gsub(/-/,"",$6); if (substr($1,0,1)=="/") { pat=substr($1,0,length($0)-1)"/"; }; if( $6 != "") {if ( $6 < oldd ) { oldd=$6; oldf=pat$8; }; print $6, pat$8; count++;}} END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'
質問が少し古くても、助けになるかもしれないと思います。
編集1:この変更により、ファイルとディレクトリをスペースで解析できます。ルート/
でそれを発行し、史上最も古いファイルを見つけるのに十分な速さです。
ls -lRU --time-style=long-iso "$PWD"/* | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { gsub(/-/,"",$6); if (substr($0,0,1)=="/") { pat=substr($0,0,length($0)-1)"/"; $6="" }; if( $6 ~ /^[0-9]+$/) {if ( $6 < oldd ) { oldd=$6; oldf=$8; for(i=9; i<=NF; i++) oldf=oldf $i; oldf=pat oldf; }; count++;}} END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'
説明したコマンド:
実行する
〜$ time ls -lRU "$ PWD"/* | awkなど.
最も古い日付:19691231
ファイル:/home/.../.../backupold/.../EXAMPLES/how-to-program.txt
比較した合計:111438
本物の0分1.135秒
ユーザー0m0.872s
sys 0m0.760s
編集2:同じ概念、アクセス時間を見てfind
を使ったより良い解決法(%T
を使って変更時刻の最初のprintf
またはのステータス変更の代わりの%C
)。
find . -wholename "*" -type f -printf "%AY%Am%Ad %h/%f\n" | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { if ($1 < oldd) { oldd=$1; oldf=$2; for(i=3; i<=NF; i++) oldf=oldf " " $i; }; count++; } END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'
編集3:以下のコマンドは、修正時刻を使用し、古くなるにつれて進行状況を表示します。これは、誤ったタイムスタンプがある場合に便利です(1970-01-01など)。
find . -wholename "*" -type f -printf "%TY%Tm%Td %h/%f\n" | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { if ($1 < oldd) { oldd=$1; oldf=$2; for(i=3; i<=NF; i++) oldf=oldf " " $i; print oldd " " oldf; }; count++; } END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'
Lsを使ってください - manページでディレクトリの順序を教えてくれます。
ls -clt | head -n 2
-n 2を指定すると、出力に「合計」は表示されません。ファイルの名前だけが欲しい場合。
ls -t | head -n 1
そして、もしあなたが通常の順序でリストを必要とするなら(最新のファイルを入手する)
ls -tr | head -n 1
Findを使用するよりもはるかに簡単で、はるかに高速で、より堅牢です。ファイルの命名形式について心配する必要はありません。ほとんどすべてのシステムで動作するはずです。
find ! -type d -printf "%T@ %p\n" | sort -n | head -n1
「最も古い」とは、ほとんどの人があなたが「最も古い修正時刻」を意味していると想定しているようです。 "最も古い"の最も厳密な解釈によれば、おそらくこれは修正されていますが、最も古いアクセス時間を持つものが必要な場合は、したがって最良の答え:
find -type f -printf '%A+ %p\n' | sort | head -n 1
%A+
に注目してください。