web-dev-qa-db-ja.com

ディレクトリツリーで最も古いファイルを見つける方法

ディレクトリツリーで最も古いファイルを見つけるためのシェルワンライナーを探しています。

70
Marius Gedminas

これは機能します(Daniel Anderssonの提案を取り入れるために更新されました):

find -type f -printf '%T+ %p\n' | sort | head -n 1
72
Marius Gedminas

これはもう少し移植性が高く、GNU find拡張子-printfに依存しないため、BSD/OS Xでも同様に機能します。

find . -type f -print0 | xargs -0 ls -ltr | head -n 1

ここでの唯一の欠点は、それがARG_MAXのサイズにいくぶん制限されているということです(はほとんどの新しいカーネルには関係ないはずです)。したがって、返されるgetconf ARG_MAX文字(私のシステムでは262,144)を超える文字がある場合、それはあなたに正しい結果を与えません。 -print0xargs -0はそうではないので、それはPOSIXにも準拠していません。

この問題に対するより多くの解決策がここに概説されています: ディレクトリ内で最新の(最新、最古、最古)ファイルを見つけるにはどうすればいいですか? - Greg's Wiki

11
slhck

以下のコマンドは、あらゆる種類の奇妙なファイル名で動作することが保証されています。

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が必要です。

関連マニュアルページ: find - grep - sed - sort - stat

11
Dennis

ここで受け入れられている答えや他の人が仕事をしていますが、あなたが非常に大きな木を持っていれば、それらすべてがファイルの束全体をソートするでしょう。

並べ替える必要なしに、それらをリストして最も古いものを追跡することができればもっと良いでしょう。

私がこの代替ソリューションを思いついたのは、その理由です。

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}'

説明したコマンド:

  • ls -lRU --time-style = long-iso "$ PWD"/*すべてのファイル(*)、長い形式(l)、再帰的に(R)、並べ替えずに高速化(U)、それをパイプでawkに出力
  • 次に、カウンタをゼロにして(この質問のオプション)、最も古い日付を今日に設定することによって開始します(YearMonthDayという形式)。
  • 最初のメインループ
    • 6番目のフィールドの日付を取得し、Year-Month-Dayの形式でYearMonthDayに変更します(lsがこのように出力しない場合は、微調整する必要があるかもしれません)。
    • 再帰的に使用すると、/ directory/here:の形式で、すべてのディレクトリのヘッダー行が表示されます。この行をpat変数に入れます。 (最後の「:」を「/」に置き換えます)。そして、有効なファイル行としてヘッダー行を使用しないように、$ 6をnoneに設定します。
    • フィールド$ 6に有効な番号がある場合はその日付。古い日付olddと比較してください。
    • 年上ですか?次に、古い日付olddと古いファイル名oldfの新しい値を保存します。ところで、oldfは8番目のフィールドだけでなく、8番目から最後までです。そのため、ループは8日からNFまで連結します(end)。
    • 前払いを1つカウントする
    • 結果を印刷して終了

実行する

〜$ 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}'
5
Dr Beco

Lsを使ってください - manページでディレクトリの順序を教えてくれます。

ls -clt | head -n 2

-n 2を指定すると、出力に「合計」は表示されません。ファイルの名前だけが欲しい場合。

ls -t | head -n 1

そして、もしあなたが通常の順序でリストを必要とするなら(最新のファイルを入手する)

ls -tr | head -n 1

Findを使用するよりもはるかに簡単で、はるかに高速で、より堅牢です。ファイルの命名形式について心配する必要はありません。ほとんどすべてのシステムで動作するはずです。

4
user1363990
find ! -type d -printf "%T@ %p\n" | sort -n | head -n1
2
Okki

「最も古い」とは、ほとんどの人があなたが「最も古い修正時刻」を意味していると想定しているようです。 "最も古い"の最も厳密な解釈によれば、おそらくこれは修正されていますが、最も古いアクセス時間を持つものが必要な場合は、したがって最良の答え:

find -type f -printf '%A+ %p\n' | sort | head -n 1

%A+に注目してください。

0
PenguinLust