サブディレクトリと時間を含むディレクトリで最新の変更されたファイルを再帰的に検索してリストする方法は?


417
  • オペレーティングシステム:Linux

  • ファイルシステムタイプ:ext3

  • 推奨される解決策:bash(script / oneliner)、ruby、python

いくつかのサブディレクトリとその中にファイルがあるいくつかのディレクトリがあります。これらすべてのディレクトリのリストを作成する必要があります。すべての第1レベルディレクトリが、その中で最後に作成/変更されたファイルの日付と時刻の隣に表示されるように構成されています。

明確にするために、ファイルに触れたり、その内容をいくつかのサブディレクトリレベルで変更したりすると、そのタイムスタンプが第1レベルのディレクトリ名の横に表示されます。次のような構造のディレクトリがあるとします。

./alfa/beta/gamma/example.txt

そして、ファイルの内容を変更しますexample.txt。その時間alfaは、エポックではなく、人間が読める形式で第1レベルのディレクトリの横に表示される必要があります。私は、検索を使用していくつかのことを試してみたxargssortと同類が、私は、私がダウンして修正ファイルに/いくつかのレベルを作成するときに「アルファ」のファイルシステムのタイムスタンプが変更されないという問題が周りに取得することはできません。


構築に苦労することができれば、github.com / shadkam / recentmostを使用できます。
user3392225 2014年

4
信じられない。16の答え、そしてほとんど/すべてがOPが指定したことを実行しようとさえしません...
hmijailは辞任者を追悼し

-Rスイッチなどの解決策の代わりに、ここではバルクを表示しています。
neverMind9 2018年

ネイティブ機能である必要があります。
neverMind9

回答:


486

これを試してください:

#!/bin/bash
find $1 -type f -exec stat --format '%Y :%y %n' "{}" \; | sort -nr | cut -d: -f2- | head

スキャンを再帰的に開始するディレクトリへのパスを指定して実行します(スペースを含むファイル名をサポートしています)。

多くのファイルがある場合、何かが返されるまでに時間がかかる場合があります。xargs代わりに使用すると、パフォーマンスを向上させることができます。

#!/bin/bash
find $1 -type f -print0 | xargs -0 stat --format '%Y :%y %n' | sort -nr | cut -d: -f2- | head

少し速いです。


132
「高速メソッド」は、print0を使用して、ファイル名のスペースやラインフィードをサポートすることもできます。find $1 -type f -print0 | xargs -0 stat --format '%Y :%y %n' | sort -nr | cut -d: -f2- | head これが私が使用するものです:これはまだ私にとっては高速です。
Dan

20
Mac OS Xでは、GNUの統計ではないため、コマンドは失敗します。あなたはする必要がありますbrew install coreutilsし、使用gstatの代わりにstat
CharlesB

36
ジョブを実行するstatので、実行する必要はありませんfind PATH -type f -printf "%T@ %p\n"| sort -nr。その方が少し速いです。
nr 2013年

4
@ user37078のコメントを実際の回答に変換したり、元の回答を編集したりできますか?それを行うには「正しい方法」[tm]のようです。
mnagel 2013

6
Mac OS Xでは、gstatや何かをインストールすることなく、あなたが行うことができます:find PATH -type f -exec stat -f "%m %N" "{}" \; | sort -nr | head
cobbzilla

198

ファイルステータスがN分前に最後に変更されたすべてのファイルを検索するには:

find -cmin -N

例えば:

find -cmin -5


4
+1ありがとう、とても便利です。GnuWin32検索を使用してWindowsで動作します。
Sabuncu 2014年

とても簡潔です。非常に素晴らしい!
ランディL

より複雑な他のソリューションよりも高速です
david.perez 2015

20
本当に良いです。たとえば、過去50日間の変更に対しては、「find -ctime -50」を使用できます。
Gorkem 2016年

1
乱雑さを除外するには、次を使用しますsudo find -cmin -1 2>&1 |grep -v /proc/
Cees Timmerman

39

GNU Find(を参照man find)には-printf、ファイルEPOC mtimeおよび相対パス名を提供するためのパラメーターがあります。

redhat> find . -type f -printf '%T@ %P\n' | sort -n | awk '{print $2}'

3
ありがとう!これは、非常に広いディレクトリ構造を妥当な時間内に検索するのに十分な速さである唯一の回答です。tail何千行も出力されないように、出力をパススルーします。
sffc 2013年

8
別のコメント:awk '{print $2}'スペースを含むファイル名がある場合、この部分は問題を引き起こすようです。ここで使用して解決するsed代わりに、それはまた、パスに加えて時刻を表示:find . -type f -printf '%T@ %Tc %P\n' | sort -n | tail | sed -r 's/^.{22}//'
SFFC

3
私はそれがソート-rnであるべきだと思います
BojanDevićMar

2
-printfバリアントは、毎回「stat」プロセスを呼び出すよりもはるかに高速です。これにより、バックアップジョブが数時間削減されます。これを知らせてくれてありがとう。ツリー内の最後の更新のみに関心があるので、awk / sedは避けました。X= $(find / path -type f -printf '%T%p \ n' | grep -v something-I- don-tcare-about | sort -nr | head -n 1)とエコー$ {X#* ""}がうまく機能しました(最初のスペースまでのものを提供してください)
David Goodwin

2
ファイル名が複数行にわたる場合、すべてが機能しません。touch "lala<Enter>b"このようなファイルを作成するために使用します。UNIXユーティリティの設計にはファイル名に関する大きな欠陥があると思います。
フルーツ

35

このワンライナーに対するハローの素晴らしい答えを短くしました

stat --printf="%y %n\n" $(ls -tr $(find * -type f))

更新:ファイル名にスペースがある場合、この変更を使用できます

OFS="$IFS";IFS=$'\n';stat --printf="%y %n\n" $(ls -tr $(find . -type f));IFS="$OFS";

これはどうですか:IFS = $ '\ n'; stat --printf = "%y%n \ n" $(ls -tr $(find。-type f))
slashdottir

3
非常に多数のファイルがある場合、これは機能しません。xargsを使用する答えはその制限を解決します。
carl verbiest、2015年

@carlverbiest確かに多数のファイルは、slashdottirのソリューションを壊します。その場合、xargsベースのソリューションでも遅くなります。user2570243のソリューションは、大きなファイルシステムに最適です。
ステフェイン・グーリッホン

IFS=$'\n'ファイル名を処理する場合、どのイベントでも安全ではありません。UNIXでは、改行はファイル名の有効な文字です。NUL文字のみがパスに存在しないことが保証されています。
チャールズダフィー

17

これを試して

#!/bin/bash
stat --format %y $(ls -t $(find alfa/ -type f) | head -n 1)

これはfind、ディレクトリからすべてのファイルを収集しls、変更日付でソートされたリストを表示しhead、最初のファイルを選択し、最後statに時刻を適切な形式で表示するために使用します。

現時点では、名前に空白やその他の特殊文字が含まれているファイルは安全ではありません。まだあなたのニーズを満たしていない場合は、表彰を書いてください。


1
halo:私はあなたの答えが好きです。うまく機能し、正しいファイルを出力します。私の場合はサブレベルが多すぎるので、私は助けにはなりません。そのため、lsに対して「引数リストが長すぎます」と表示されます。この場合も、xargsは役に立ちません。他のことを試してみます。
fredrik

その場合は少し複雑で、実際のプログラムが必要になります。Perlをハックします。
DanielBöhmer、2011

1
代わりにPHPを使用してこれを解決しました。ファイルシステムツリーを下降し、最後に変更されたファイルの時刻を格納する再帰関数。
fredrik

11

このコマンドはMac OS Xで機能します。

find "$1" -type f -print0 | xargs -0 stat --format '%Y :%y %n' | sort -nr | cut -d: -f2- | head

Linuxでは、元の投稿者が尋ねたように、のstat代わりにを使用しますgstat

もちろん、この回答はuser37078の優れたソリューションであり、コメントから完全な回答に昇格しました。CharlesBの洞察をgstatMac OS Xで使用することを混ぜ合わせました。ちなみに、homebrewではなくMacPortsからcoreutilsを入手しました。

そして、これ~/bin/ls-recent.shを再利用のためにこれを単純なコマンドにパッケージ化した方法を次に示します。

#!/bin/bash
# ls-recent: list files in a dir tree, most recently modified first
#
# Usage: ls-recent path [-10 | more]
# 
# Where "path" is a path to target directory, "-10" is any arg to pass
# to "head" to limit the number of entries, and "more" is a special arg
# in place of "-10" which calls the pager "more" instead of "head".
if [ "more" = "$2" ]; then
   H=more; N=''
else
   H=head; N=$2
fi

find "$1" -type f -print0 |xargs -0 gstat --format '%Y :%y %n' \
    |sort -nr |cut -d: -f2- |$H $N

2
OS Xヨセミテ上; エラーが発生する:検索:ftsopen:そのようなファイルやディレクトリはありません
Reece

面白い。入力したコマンド(パラメーター付き)は何ですか?そして、そのディレクトリ内のファイルの名前は何でしたか?また、独自のバージョンのを作成した場合~/bin/ls-recent.sh、スクリプトの違いを注意深く確認しましたか?
Jim DeLaHunt、2016

10
Mac OS Xに何もインストールしたくない場合:find . -exec stat -f '%m%t%Sm %N' {} + | sort -n | cut -f2-
Jake

5

この投稿のperlとPythonの両方のソリューションは、Mac OS Xでのこの問題の解決に役立ちました:https : //unix.stackexchange.com/questions/9247/how-to-list-files-sorted-by-modification-date-recursively -no-stat-command-avail

投稿からの引用:

Perl:

find . -type f -print |
perl -l -ne '
    $_{$_} = -M;  # store file age (mtime - now)
    END {
        $,="\n";
        print sort {$_{$b} <=> $_{$a}} keys %_;  # print by decreasing age
    }'

Python:

find . -type f -print |
python -c 'import os, sys; times = {}
for f in sys.stdin.readlines(): f = f[0:-1]; times[f] = os.stat(f).st_mtime
for f in sorted(times.iterkeys(), key=lambda f:times[f]): print f'

5

隠しファイルを無視—タイムスタンプが素晴らしく高速

ファイル名のスペースをうまく処理します—それらを使用するべきではありません!

$ find . -type f -not -path '*/\.*' -printf '%TY.%Tm.%Td %THh%TM %Ta %p\n' |sort -nr |head -n 10

2017.01.28 07h00 Sat ./recent
2017.01.21 10h49 Sat ./hgb
2017.01.16 07h44 Mon ./swx
2017.01.10 18h24 Tue ./update-stations
2017.01.09 10h38 Mon ./stations.json

findリンクをたどると、より多くの情報を見つけることができます。


3

私は最新のアクセス時間についてこれを示していますが、これを簡単に変更して最新のmod時間を実行できます。

これを行うには2つの方法があります。


1)数千万のファイルがある場合にコストがかかる可能性があるグローバルな並べ替えを避けたい場合は、次のようにします(検索を開始するディレクトリのルートに自分自身を配置します)。

linux> touch -d @0 /tmp/a;
linux> find . -type f -exec tcsh -f -c test `stat --printf="%X" {}` -gt  `stat --printf="%X" /tmp/a`  ; -exec tcsh -f -c touch -a -r {} /tmp/a ; -print 

上記の方法は、ファイル名を次第に新しいアクセス時間で印刷し、最後に印刷するファイルは、最新のアクセス時間を持つファイルです。「tail -1」を使用すると、最新のアクセス時間を取得できます。


2)findを使用して、サブディレクトリ内のすべてのファイルの名前、アクセス時間を再帰的に出力し、アクセス時間と末尾の最大エントリに基づいて並べ替えることができます。

linux> \find . -type f -exec stat --printf="%X  %n\n" {} \; | \sort -n | tail -1

そして、あなたはそれを持っています...


3

私はよく使用する.profileにこのエイリアスがあります

$ alias | grep xlogs
xlogs='sudo find . \( -name "*.log" -o -name "*.trc" \) -mtime -1 | sudo xargs ls -ltr --color | less -R'

したがって、あなたが探しているものを実行します(例外として、日付/時刻の複数のレベルを変更することはありません)-最新のファイル(この場合は* .logおよび* .trcファイル)を探します。また、最終日に変更されたファイルのみを検索し、時間でソートし、出力をlessにパイプします。

sudo find . \( -name "*.log" -o -name "*.trc" \) -mtime -1 | sudo xargs ls -ltr --color | less -R

ps。一部のサーバーにはrootがありませんが、常にsudoがあるため、その部分は必要ない場合があります。


これは「まさにあなたが探しているもの」ですか?OPは彼が何を望んだかについての良い説明を書きました、そしてこれは完全にそれを無視します。
hmijailが辞任者を悼む

それを指摘してくれてありがとう。あなたが正しい-このメソッドは変更日付/時刻を取得するために複数のレベルに行くのではなく、その中のディレクトリのファイルの日付/時刻を表示するだけです。私の答えを編集しました。
Tagar 2017年

1

あなたはprintfコマンドを試してみてください

%Ak kで指定された形式のファイルの最終アクセス時刻@' or a directive for the C 。これはstrftime関数のいずれかです。kに可能な値は以下のとおりです。システム間の「strftime」の違いにより、一部のシステムでは使用できない場合があります。


1

クイックバッシュ機能:

# findLatestModifiedFiles(directory, [max=10, [format="%Td %Tb %TY, %TT"]])
function findLatestModifiedFiles() {
    local d="${1:-.}"
    local m="${2:-10}"
    local f="${3:-%Td %Tb %TY, %TT}"

    find "$d" -type f -printf "%T@ :$f %p\n" | sort -nr | cut -d: -f2- | head -n"$m"
}

ディレクトリで最新の変更されたファイルを見つけます。

findLatestModifiedFiles "/home/jason/" 1

3番目の引数として独自の日付/時刻形式を指定することもできます。


1

次の例では、タイムスタンプの文字列と最新のタイムスタンプを含むファイルの名前を返します。

find $Directory -type f -printf "%TY-%Tm-%Td-%TH-%TM-%TS %p\n" | sed -r 's/([[:digit:]]{2})\.([[:digit:]]{2,})/\1-\2/' |     sort --field-separator='-' -nrk1 -nrk2 -nrk3 -nrk4 -nrk5 -nrk6 -nrk7 | head -n 1

次の形式の出力になります。 <yy-mm-dd-hh-mm-ss.nanosec> <filename>


1

以下は、スペース、改行、グロブ文字を含む可能性のあるファイル名で機能する1つのバージョンです。

find . -type f -printf "%T@ %p\0" | sort -zk1nr
  • find ... -printf ファイルの変更(EPOCH値)に続いてスペースを出力し、 \0終了したファイル名を出力します。
  • sort -zk1nr NULで終了したデータを読み取り、数値で逆順にソートします

Linuxでタグ付けされているので、私は仮定しています gnu utilsが使用可能であるとています。

あなたは上でパイプすることができます:

xargs -0 printf "%s\n"

改行で終了した変更時刻(最新のものが最初)でソートされた変更時刻とファイル名を出力します。


1

これは私が使用しているものです(非常に効率的です):

function find_last () { find "${1:-.}" -type f -printf '%TY-%Tm-%Td %TH:%TM %P\n' 2>/dev/null | sort | tail -n "${2:-10}" }

長所:

  • 3つのプロセスのみを生成します

使用法:

find_last [dir [number]]

どこ:

  • dir -検索するディレクトリ[current dir]
  • number -表示する最新のファイル数[10]

の出力はfind_last /etc 4次のようになります。

2019-07-09 12:12 cups/printers.conf
2019-07-09 14:20 salt/minion.d/_schedule.conf
2019-07-09 14:31 network/interfaces
2019-07-09 14:41 environment

0

プレーンなls出力には、これを使用します。引数リストがないため、長くなりすぎません。

find . | while read FILE;do ls -d -l "$FILE";done

そしてcut、日付、時刻、名前だけを使って、

find . | while read FILE;do ls -d -l "$FILE";done | cut --complement -d ' ' -f 1-5

編集:現在のトップの回答が変更日でソートされていることに気づきました。これは、ここでの2番目の例と同じくらい簡単です。変更日が各行の最初なので、並べ替えを最後にスラップします。

find . | while read FILE;do ls -d -l "$FILE";done | cut --complement -d ' ' -f 1-5 | sort

0

これは、bashの再帰関数でも実行できます

Fを、辞書式にソート可能なyyyy-mm-ddなどでなければならないファイルの時間を表示する関数にします(osに依存しますか?)

F(){ stat --format %y "$1";}                # Linux
F(){ ls -E "$1"|awk '{print$6" "$7}';}      # SunOS: maybe this could be done easier

Rディレクトリを介して実行する再帰関数

R(){ local f;for f in "$1"/*;do [ -d "$f" ]&&R $f||F "$f";done;}

そして最後に

for f in *;do [ -d "$f" ]&&echo `R "$f"|sort|tail -1`" $f";done
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.