How to recursively find and list the latest modified files in a directory with subdirectories and times?
操作系统:Linux
文件系统类型:ext3
首选解决方案:bash(script/oneliner)、ruby、python
我有几个目录,其中有几个子目录和文件。我需要列出所有这些目录,这些目录的构造方式使得每个一级目录都列在其中最新创建/修改文件的日期和时间旁边。
为了澄清,如果我触摸一个文件或者向下修改它的内容几个子目录级,那么时间戳应该显示在第一级目录名的旁边。假设我有一个这样的目录:
1 | ./alfa/beta/gamma/example.txt |
我修改了文件
试试这个:
1 2 | #!/bin/bash find $1 -type f -exec stat --format '%Y :%y %n'"{}" \; | sort -nr | cut -d: -f2- | head |
使用目录的路径执行它,在该目录中它应该开始递归扫描(它支持带空格的文件名)。
如果文件太多,可能需要一段时间才能返回任何内容。如果我们使用
1 2 | #!/bin/bash find $1 -type f -print0 | xargs -0 stat --format '%Y :%y %n' | sort -nr | cut -d: -f2- | head |
速度快一点。
要查找上次在n分钟前更改文件状态的所有文件,请执行以下操作:
例如:
gnu find(见
1 2 | redhat> find . -type f -printf '%T@ %P ' | sort -n | awk '{print $2}' |
我缩短了Halo对这一行的精彩回答
1 2 | stat --printf="%y %n " $(ls -tr $(find * -type f)) |
更新:如果文件名中有空格,可以使用此修改
1 2 3 | OFS="$IFS";IFS=$' ';stat --printf="%y %n " $(ls -tr $(find . -type f));IFS="$OFS"; |
试试这个
1 2 | #!/bin/bash stat --format %y $(ls -t $(find alfa/ -type f) | head -n 1) |
它使用
此时,对于名称中带有空格或其他特殊字符的文件来说,这是不安全的。如果还不能满足你的需要,写一封推荐信。
此命令在Mac OS X上工作:
在Linux上,正如最初的海报所要求的那样,使用
当然,这个答案是用户37078出色的解决方案,从评论提升到了完整的答案。我混合了Charlesb在MacOSX上使用
下面是我如何将它打包成一个简单的命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #!/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-sorted-by-modification-date-recursively-no-stat-command-availy。
从文章中引用:
Perl:
1 2 3 4 5 6 7 8 | find . -type f -print | perl -l -ne ' $_{$_} = -M; # store file age (mtime - now) END { $,=" "; print sort {$_{$b} <=> $_{$a}} keys %_; # print by decreasing age }' |
Python:
1 2 3 4 | 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' |
我在显示最新的访问时间,你可以很容易地修改这个做最新的修改时间。
有两种方法可以做到这一点:
1)如果你想避免全局排序,如果你有数以亿计的文件,那么你可以这样做:(把你自己放在你想要搜索开始的目录的根目录中)
1 2 | 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)您可以找到递归打印子目录中所有文件的名称、访问时间,然后根据访问时间和尾部排序最大的条目:
1 2 | linux> \find . -type f -exec stat --printf="%X %n " {} \; | \sort -n | tail -1 |
就在这里,你有它……
我的.profile中有这个别名,我经常使用它
1 2 | $ alias | grep xlogs xlogs='sudo find . \( -name"*.log" -o -name"*.trc" \) -mtime -1 | sudo xargs ls -ltr --color | less -R' |
因此,它执行您正在查找的操作(但不遍历多个级别的更改日期/时间)-查找最新的文件(本例中为日志文件和*.trc文件);此外,它只查找在最后一天修改的文件,然后按时间排序,并通过更少的管道输出:
1 | sudo find . \( -name"*.log" -o -name"*.trc" \) -mtime -1 | sudo xargs ls -ltr --color | less -R |
注意,有些服务器上没有根目录,但总是有sudo,所以您可能不需要这个部分。
忽略隐藏的文件-具有良好和快速的时间戳
文件名中的空格处理得很好-不应该使用这些空格!
1 2 3 4 5 6 7 8 | $ find . -type f -not -path '*/\.*' -printf '%TY.%Tm.%Td %THh%TM %Ta %p ' |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 |
通过链接可以找到更多的
快速撞击功能:
1 2 3 4 5 6 7 8 9 | # 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 " | sort -nr | cut -d: -f2- | head -n"$m" } |
在目录中查找最新修改的文件:
1 | findLatestModifiedFiles"/home/jason/" 1 |
您还可以将自己的日期/时间格式指定为第三个参数。
下面返回一个时间戳字符串和带有最新时间戳的文件名:
1 2 | find $Directory -type f -printf"%TY-%Tm-%Td-%TH-%TM-%TS %p " | sed -r 's/([[:digit:]]{2})\.([[:digit:]]{2,})/\1-\2/' | sort --field-separator='-' -nrk1 -nrk2 -nrk3 -nrk4 -nrk5 -nrk6 -nrk7 | head -n 1 |
生成窗体的输出:
这里有一个版本可以处理文件名,其中可能包含空格、换行符、全局字符:
1 | find . -type f -printf"%T@ %p\0" | sort -zk1nr |
find ... -printf 打印文件修改(epoch值),后跟空格和\0 终止的文件名。sort -zk1nr 读取nul终止的数据,并对其进行逆向排序。
因为问题是用Linux标记的,所以我假设
你可以在上面用管道输送:
1 2 | xargs -0 printf"%s " |
打印由换行符终止的修改时间(最近的第一个)排序的修改时间和文件名。
对于普通
1 | find . | while read FILE;do ls -d -l"$FILE";done |
和
1 | find . | while read FILE;do ls -d -l"$FILE";done | cut --complement -d ' ' -f 1-5 |
编辑:刚刚注意到,当前最热门的答案按修改日期排序。这里的第二个例子也很简单,因为修改日期是每行的第一个-在末尾加上一个排序:
1 | find . | while read FILE;do ls -d -l"$FILE";done | cut --complement -d ' ' -f 1-5 | sort |
您可以给printf命令find a try
%Ak File's last access time in
the format specified by k,
which is either@' or a directive for the C strftime'
function. The possible values for k are listed
below;
some of them might not be available on all
systems, due
to differences in `strftime' between systems.
这也可以通过bash中的reccursive函数来实现。
让f一个函数来显示文件的时间,该时间必须在字典中可排序,例如,yyyy-mm-dd等(取决于操作系统?)
1 2 | F(){ stat --format %y"$1";} # Linux F(){ ls -E"$1"|awk '{print$6""$7}';} # SunOS: maybe this could be done easier |
r在目录中运行的递归函数
1 | R(){ local f;for f in"$1"/*;do [ -d"$f" ]&&R $f||F"$f";done;} |
最后
1 | for f in *;do [ -d"$f" ]&&echo `R"$f"|sort|tail -1`" $f";done |