web-dev-qa-db-ja.com

変更された日付で最新のファイルを見つける

サブディレクトリを含む(大きな)ディレクトリで最新のファイル(mtime)を検索する場合、どうすればよいですか?

私が見つけた多くの投稿は、ls -lt | headのいくつかのバリエーションを提案します(面白いことに、多くの人がls -ltr | tailを提案しますが、これは同じですが効率は劣ります)。

それからまた、できます

find . -type f -exec ls -lt \{\} \+ | head

1つのコマンドで指定できる限り多くのファイルに対してトリックを確実に行います。つまり、bigディレクトリがある場合、-exec...\+は個別のコマンドを発行します。したがって、各グループはグループ内でlsでソートされますが、合計セットではソートされません。したがって、ヘッドは最初のバッチの最後のエントリを取得します。

答えはありますか?

36
Rich

ls-printfアクションを介して必要なことをすべて実行できるため、外部コマンド(findとして)を繰り返す必要はありません。

find /path -printf '%T+ %p\n' | sort -r | head
43
enzotib

今日も同様の問題がありましたが、findなしで攻撃しました。ホームディレクトリで最後に編集したファイルを返すために、sshを実行できる短いものが必要でした。これは私が思いついたものです。

ls -tp | grep -v /$ | head -1

ls-pオプションはディレクトリに末尾のスラッシュを追加し、grep -vはスラッシュで終わる行(別名、すべてのディレクトリ)を削除し、head -1は出力を制限します単一のファイル。

ファイル名だけを返す場合は、findを使用するよりもはるかに冗長です。

8
Pat Regan

これは私のシステムではprintfより高速ですが、理由はわかりませんが

find /path -type f -exec stat -c "%y %n" {} + | sort -r | head
4
arrange

編集:この投稿は、私が思ったほど「特に有用ではない」とは思いません。これは、ファイルのリスト全体をソートするのではなく、最後に変更されたファイルを追跡するだけの非常に高速なソリューションです。

find . -type f -printf '%T@ %p\n' | awk 'BEGIN { mostrecenttime = 0; mostrecentline = "nothing"; } { if ($1 > mostrecenttime) { mostrecenttime = $1; mostrecentline = $0; } } END { print mostrecentline; }' | cut -f2- -d ' '

わかりやすくするために複数の行に展開します。次のようになります。

find . -type f -printf '%T@ %p\n' | awk '
    BEGIN { mostrecenttime = 0; mostrecentline = "nothing"; }
    {
        if ($1 > mostrecenttime)
            { mostrecenttime = $1; mostrecentline = $0; }
    }
    END { print mostrecentline; }' | cut -f2- -d ' '

編集の終わり


特に有用な投稿ではありませんが、「アレンジ」が速度について議論しているので、これを共有すると思いました。

arrangeおよびEnzotibのソリューションでは、ディレクトリ内のすべてのファイルをmtimesでリストしてからソートします。ご存じのとおり、最大値を見つけるためにソートは必要ありません。最大値の検索は線形時間で実行できますが、ソートにはn log(n)時間かかります[違いはそれほど多くないが、それでも;)]。これをうまく実装する方法は考えられません。 [編集:きれいな(ただし汚い見た目)で高速な実装が上記で提供されています。

次善策-ディレクトリ内で最後に編集されたファイルを見つけるには、各レベル1サブディレクトリで最後に編集されたファイルを再帰的に見つけます。このファイルがサブディレクトリを表すようにします。次に、レベル1のサブディレクトリの代表とともにレベル1のファイルを並べ替えます。各ディレクトリのレベル1ファイルとサブディレクトリの数がほぼ一定の場合、このプロセスはファイルの総数に比例してスケーリングする必要があります。

これは私がこれを実装するために思いついたものです:

findrecent() { { find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1; }
findrecent .

これを実行すると、find: findrecent: No such file or directoryエラーが大量に発生しました。理由:findの-execが別のシェルで実行されます。 .bashrc、.xsessionrcでfindrecentを定義しようとしましたが、これらは助けにはなりませんでした[ここに助けていただければ幸いです]。最後に私はパッティングに頼った

#!/bin/bash
{ find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1;

pATHのfindrecentというスクリプトで実行します。

私はこれを実行し、何も出力せずに待ち続けました。ただ、無限ループを処理していないことを確認するために、ファイルを

#!/bin/bash
echo "$1" >&2
{ find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1;

そして再試行しました。それはうまくいきましたが、私のホームフォルダで1分35秒かかりました-Arrangeとenzotibのソリューションはそれぞれ1.69、1.95秒かかりました!

O(n)のO(n log(n))に対する優位性はこれだけです!くそー関数呼び出しのオーバーヘッド! [むしろ、スクリプト呼び出しのオーバーヘッド]

しかし、このスクリプトは以前のソリューションよりも優れた拡張性を備えており、Googleのメモリバンクで実行するよりも速く実行されるに違いありません; D

2
S Prasanth

それほどファッショナブルではありませんが、Midnight Commander:*を検索し、結果をパネル化して、変更時刻を逆順に並べ替えることでこれを実現することもできます。

明らかに、それはfindより少し遅いです-922000ファイルを含む私のホームディレクトリは、mcで5分未満しか使用されませんでしたが、ほぼ14分でfindでソートされました。

  • 私はおそらく、適切な検索呼び出しを発明するための9分の差よりも長い時間を費やすでしょう。

  • エラーの可能性が低い(ソートなどに-rを指定するのを忘れた-もう一度開始)

  • ソート順などを変更することで結果セットを再生することができます-ファイルを再クエリすることなく。

  • 結果セットからsomeファイルに対してのみファイル操作を実行できます-つまり、サイズでソートし、不要ないくつかの大きなファイルを削除します

1
Sergey

Perlとともにconjonctinでfindを使用します。

 find my_directory -type f -printf '%T@\t%p\n' | Perl -ane '@m=@F if ($F[0]>$m[0]); END{print $m[1];}'

最もエポック==が最後に変更されたファイルの名前を取得します。

1
MUY Belgium