web-dev-qa-db-ja.com

サブディレクトリと時間を含むディレクトリ内で最新の変更ファイルを再帰的に検索して一覧表示する方法

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

  • ファイルシステムの種類:ext3

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

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

わかりやすくするために、ファイルに触れたり、その内容をサブディレクトリの数レベル下まで変更したりすると、そのタイムスタンプは最初のレベルのディレクトリ名の横に表示されるはずです。このような構造のディレクトリがあるとします。

./alfa/beta/gamma/example.txt

そして私はファイルexample.txtの内容を修正します、その時はEpochではなく、人間が読める形式で第一レベルディレクトリalfaの隣に表示される必要があります。 find、xargssortなどを使用していくつかのことを試してみましたが、ファイルを2、3レベル下げてもファイルシステムのタイムスタンプが変わらないという問題を回避することはできません。

364
fredrik

これを試してください。

#!/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

これは少し速いです。

427
Heppo

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

find -cmin -N

例えば:

find -cmin -5

168
iman

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

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

私はこのワンライナーへのハローの素晴らしい答えを短くしました

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";
33
slashdottir

これを試して

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

ディレクトリからすべてのファイルを収集するためにfindを、変更日順にソートするためにlsを使用し、最初のファイルを選択するためにheadを使用し、最後にNiceフォーマットで時刻を表示するためにstatを使用します。

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

13
Daniel Böhmer

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

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

Linuxでは、元のポスターが尋ねたように、statの代わりにgstatを使用します。

もちろん、この回答は ser37078 の優れたソリューションであり、コメントから完全な回答に昇格されています。 Mac OS Xでgstatを使用するために CharlesB の洞察を混ぜました。 MacPorts からcoreutilsを取得しました homebrew ではなく、ところで。

そして、再利用のためにこれを簡単なコマンド~/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
10
Jim DeLaHunt

この投稿のPerlとPythonの両方のソリューションは、Mac OS Xでこの問題を解決するのに役立ちました。 https://unix.stackexchange.com/questions/9247/how-to-list-files -修正日でソート-再帰的-統計なし-コマンド-使用可能

投稿からの引用:

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
William Niu

これは最新のアクセス時間を示しています。最新の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)サブディレクトリ内のすべてのファイルの名前、アクセス時間を再帰的に表示してから、アクセス時間に基づいてソートし、最後に最も大きいエントリをソートすることができます。

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

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

3
Sean

私は私の.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を持っているので、あなたはその部分を必要としないかもしれません。

3
Tagar

隠しファイルを無視する - Nice&fastタイムスタンプ付き

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

$ 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 リンクをたどることで見つけることができます。

2

これは、スペース、改行、glob文字を含む可能性のあるファイル名で動作するバージョンです。

find . -type f -printf "%T@ %p\0" | sort -zk1nr
  • find ... -printfは、ファイル変更(エポック値)の後にスペースと\0で終わるファイル名を出力します。
  • sort -zk1nrは、NUL終了データを読み込み、それを数字の逆順にソートします。

質問はLinuxでタグ付けされているので、私はgnu utilsが利用可能であると思います。

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

xargs -0 printf "%s\n"

変更時刻とファイル名を変更時刻順(最新のものから順)にソートして、改行で終了するように表示します。

1
anubhava

クイックバッシュ機能:

# 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
Jason Larke

以下は、タイムスタンプの文字列と最新のタイムスタンプを持つファイルの名前を返します。

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
mark_infinite

あなたは試しを見つけるのprintfコマンドを与えることができます

%Akファイルの最後のアクセス時刻(kで指定された形式)。これは@' or a directive for the Cstrftime関数です。 kの可能な値は以下の通りです。システム間の `strftime 'の違いのために、それらのいくつかはすべてのシステムで利用できるわけではないかもしれません。

0
graugans

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

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-検索するディレクトリ[現在のディレクトリ]
  • 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
Seweryn Niemiec

これはbashの再帰関数でも可能です。

辞書式にソート可能でなければならないファイルの時刻を表示する関数をFとします(os-dependent?)。

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

ディレクトリを通る再帰関数

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

_ edit _ :現在のトップアンサーが変更日順にソートされていることに気付いただけです。変更日は各行の最初にあるので、これは2番目の例と同じくらい簡単です - 最後までソートをたたいてください:

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