オペレーティングシステム:Linux
ファイルシステムの種類:ext3
推奨される解決策:bash(script/oneliner)、Ruby、python
いくつかのサブディレクトリとファイルを含むいくつかのディレクトリがあります。すべての第1レベルのディレクトリがその中の最新の作成/変更されたファイルの日時の隣にリストされるような方法で構築されたこれらすべてのディレクトリのリストを作る必要があります。
わかりやすくするために、ファイルに触れたり、その内容をサブディレクトリの数レベル下まで変更したりすると、そのタイムスタンプは最初のレベルのディレクトリ名の横に表示されるはずです。このような構造のディレクトリがあるとします。
./alfa/beta/gamma/example.txt
そして私はファイルexample.txt
の内容を修正します、その時はEpochではなく、人間が読める形式で第一レベルディレクトリalfa
の隣に表示される必要があります。 find、xargs
、sort
などを使用していくつかのことを試してみましたが、ファイルを2、3レベル下げてもファイルシステムのタイムスタンプが変わらないという問題を回避することはできません。
これを試してください。
#!/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
これは少し速いです。
ファイルステータスが最後に変更されたすべてのファイルを検索するには _ n _ 分前:
find -cmin -N
例えば:
find -cmin -5
GNU Find(man find
を参照)には、EPOC mtimeファイルと相対パス名を表示するための-printf
パラメータがあります。
redhat> find . -type f -printf '%T@ %P\n' | sort -n | awk '{print $2}'
私はこのワンライナーへのハローの素晴らしい答えを短くしました
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";
これを試して
#!/bin/bash
stat --format %y $(ls -t $(find alfa/ -type f) | head -n 1)
ディレクトリからすべてのファイルを収集するためにfind
を、変更日順にソートするためにls
を使用し、最初のファイルを選択するためにhead
を使用し、最後にNiceフォーマットで時刻を表示するためにstat
を使用します。
現時点では、名前に空白や他の特殊文字が含まれているファイルには安全ではありません。それがまだあなたのニーズを満たしていない場合は、称賛を書く。
このコマンドは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
この投稿の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'
これは最新のアクセス時間を示しています。最新の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
そして、あなたはそれを持っています...
私は私の.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を持っているので、あなたはその部分を必要としないかもしれません。
ファイル名のスペースをうまく処理します - それらを使うべきではありません!
$ 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
リンクをたどることで見つけることができます。
これは、スペース、改行、glob文字を含む可能性のあるファイル名で動作するバージョンです。
find . -type f -printf "%T@ %p\0" | sort -zk1nr
find ... -printf
は、ファイル変更(エポック値)の後にスペースと\0
で終わるファイル名を出力します。sort -zk1nr
は、NUL終了データを読み込み、それを数字の逆順にソートします。質問はLinuxでタグ付けされているので、私はgnu
utilsが利用可能であると思います。
あなたは上記でパイプすることができます:
xargs -0 printf "%s\n"
変更時刻とファイル名を変更時刻順(最新のものから順)にソートして、改行で終了するように表示します。
クイックバッシュ機能:
# 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番目の引数として独自の日付/時刻形式を指定することもできます。
以下は、タイムスタンプの文字列と最新のタイムスタンプを持つファイルの名前を返します。
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>
あなたは試しを見つけるのprintfコマンドを与えることができます
%Akファイルの最後のアクセス時刻(kで指定された形式)。これは
@' or a directive for the C
strftime関数です。 kの可能な値は以下の通りです。システム間の `strftime 'の違いのために、それらのいくつかはすべてのシステムで利用できるわけではないかもしれません。
これは私が使用しているものです(非常に効率的です):
function find_last () { find "${1:-.}" -type f -printf '%TY-%Tm-%Td %TH:%TM %P\n' 2>/dev/null | sort | tail -n "${2:-10}" }
長所:
使用法:
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
これは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
単純な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