简体   繁体   English

如何递归查找并列出具有子目录和时间的目录中的最新修改文件

[英]How to recursively find and list the latest modified files in a directory with subdirectories and times

  • Operating system: Linux操作系统:Linux

  • Filesystem type: ext3文件系统类型: ext3

  • Preferred solution: Bash (script/one-liner), Ruby, or Python首选解决方案:Bash(脚本/单行)、Ruby 或 Python

I have several directories with several subdirectories and files in them.我有几个目录,其中有几个子目录和文件。 I need to make a list of all these directories that is constructed in a way such that every first-level directory is listed next to the date and time of the latest created/modified file within it.我需要列出所有这些目录,这些目录的构建方式使得每个一级目录都列在其中最新创建/修改文件的日期和时间旁边。

To clarify, if I touch a file or modify its contents a few subdirectory levels down, that timestamp should be displayed next to the first-level directory name.为了澄清,如果我触摸一个文件或修改它的内容几个子目录级别,该时间戳应该显示在第一级目录名称旁边。 Say I have a directory structured like this:假设我有一个结构如下的目录:

./alfa/beta/gamma/example.txt

and I modify the contents of the file example.txt , I need that time displayed next to the first-level directory alfa in human readable form, not epoch.我修改了文件example.txt的内容,我需要以人类可读的形式显示在一级目录alfa旁边的时间,而不是纪元。 I've tried some things using find, xargs , sort and the like, but I can't get around the problem that the filesystem timestamp of 'alfa' doesn't change when I create/modify files a few levels down.我已经使用 find、 xargssort等尝试了一些事情,但是当我创建/修改文件向下几级时,我无法解决“alfa”的文件系统时间戳不会改变的问题。

Try this one:试试这个:

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

Execute it with the path to the directory where it should start scanning recursively (it supports filenames with spaces).使用它应该开始递归扫描的目录的路径执行它(它支持带空格的文件名)。

If there are lots of files it may take a while before it returns anything.如果有很多文件,它可能需要一段时间才能返回任何内容。 Performance can be improved if we use xargs instead:如果我们改用xargs可以提高性能:

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

which is a bit faster.这有点快。

To find all files whose file status was last changed N minutes ago:要查找N分钟前最后更改文件状态的所有文件:

find -cmin -N

For example:例如:

find -cmin -5

Use -ctime instead of -cmin for days:使用-ctime而不是-cmin几天:

find -ctime -3

On FreeBSD and MacOS : You can also use -ctime n[smhdw] for seconds, minutes, hours, days, and weeks.在 FreeBSD 和 MacOS 上:您还可以使用-ctime n[smhdw]表示秒、分钟、小时、天和周。 Days is the default if no unit is provided.如果未提供单位,则默认天数。

Examples:例子:

# FreeBSD and MacOS only:
find . -ctime -30s
find . -ctime -15
find . -ctime -52w

GNU find(参见man find )有一个-printf参数,用于在 Epoch mtime 和相对路径名中显示文件。

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

I shortened Daniel Böhmer's awesome answer to this one-liner:我缩短了Daniel Böhmer 对这条单线的精彩回答

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

If there are spaces in filenames, you can use this modification:如果文件名中有空格,您可以使用此修改:

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

Try this:尝试这个:

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

It uses find to gather all files from the directory, ls to list them sorted by modification date, head for selecting the first file and finally stat to show the time in a nice format.它使用find从目录中收集所有文件,使用ls按修改日期排序列出它们,使用head选择第一个文件,最后使用stat以漂亮的格式显示时间。

At this time it is not safe for files with whitespace or other special characters in their names.目前,名称中包含空格或其他特殊字符的文件是不安全的。 Write a commend if it doesn't meet your needs yet.如果它还不能满足您的需求,请写一个表扬。

This command works on Mac OS X:此命令适用于 Mac OS X:

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

On Linux, as the original poster asked, use stat instead of gstat .在 Linux 上,正如原始发帖人所要求的,使用stat而不是gstat

This answer is, of course, user37078 's outstanding solution, promoted from comment to full answer.这个答案当然是user37078的出色解决方案,从评论提升为完整答案。 I mixed in CharlesB 's insight to use gstat on Mac OS X. I got coreutils from MacPorts rather than Homebrew , by the way.我混合了 CharlesB 在 Mac OS X 上使用gstat的见解。顺便说gstat ,我从MacPorts而不是Homebrew获得了coreutils

And here's how I packaged this into a simple command ~/bin/ls-recent.sh for reuse:以下是我如何将其打包成一个简单的命令~/bin/ls-recent.sh以供重用:

#!/bin/bash
# ls-recent: list files in a directory tree, most recently modified first
#
# Usage: ls-recent path [-10 | more]
#
# Where "path" is a path to target directory, "-10" is any argument to pass
# to "head" to limit the number of entries, and "more" is a special argument
# 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

Ignoring hidden files — with nice & fast time stamp忽略隐藏文件 - 带有漂亮和快速的时间戳

Here is how to find and list the latest modified files in a directory with subdirectories.以下是如何在包含子目录的目录中查找和列出最新修改的文​​件。 Hidden files are ignored on purpose.隐藏文件被故意忽略。 Whereas spaces in filenames are handled well — not that you should use those!而文件名中的空格处理得很好——不是你应该使用那些! The time format can be customised.时间格式可以自定义。

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

2017.01.25 18h23 Wed ./indenting/Shifting blocks visually.mht
2016.12.11 12h33 Sun ./tabs/Converting tabs to spaces.mht
2016.12.02 01h46 Fri ./advocacy/2016.Vim or Emacs - Which text editor do you prefer?.mht
2016.11.09 17h05 Wed ./Word count - Vim Tips Wiki.mht

More find galore can be found by following the link.可以通过以下链接找到更多find

This is what I'm using (very efficient):这就是我正在使用的(非常有效):

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

PROS:优点:

  • it spawns only 3 processes它只产生 3 个进程

USAGE:用法:

find_last [dir [number]]

where:在哪里:

  • dir - a directory to be searched [current dir] dir - 要搜索的目录 [当前目录]
  • number - number of newest files to display [10] number - 要显示的最新文件数 [10]

Output for find_last /etc 4 looks like this: 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

Both the Perl and Python solutions in this post helped me solve this problem on Mac OS X:这篇文章中的 Perl 和 Python 解决方案都帮助我在 Mac OS X 上解决了这个问题:

How to list files sorted by modification date recursively (no stat command available!) 如何递归地列出按修改日期排序的文件(没有可用的 stat 命令!)

Quoting from the post:引用帖子:

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

Here is one version that works with filenames that may contain spaces, newlines, and glob characters as well:这是一个适用于可能包含空格、换行符和全局字符的文件名的版本:

find . -type f -printf "%T@ %p\0" | sort -zk1nr
  • find ... -printf prints the file modification time ( Epoch value ) followed by a space and \0 terminated filenames. find ... -printf打印文件修改时间( Epoch 值),后跟空格和\0终止的文件名。
  • sort -zk1nr reads NUL terminated data and sorts it reverse numerically sort -zk1nr读取 NUL 终止的数据并按数字倒序排序

As the question is tagged with Linux, I am assuming GNU Core Utilities are available.由于这个问题是用 Linux 标记的,我假设GNU Core Utilities是可用的。

You can pipe the above with:您可以通过以下方式对上述内容进行管道传输:

xargs -0 printf "%s\n"

to print the modification time and filenames sorted by modification time (most recent first) terminated by newlines.打印修改时间和按修改时间排序的文件名(最近的第一个),由换行符终止。

I'm showing this for the latest access time, and you can easily modify this to do latest modification time.我显示的是最新的访问时间,您可以轻松地修改它以进行最新的修改时间。

There are two ways to do this:有两种方法可以做到这一点:


  1. If you want to avoid global sorting which can be expensive if you have tens of millions of files, then you can do (position yourself in the root of the directory where you want your search to start):如果您想避免全局排序,如果您有数千万个文件,这可能会很昂贵,那么您可以这样做(将自己定位在您希望开始搜索的目录的根目录中):

     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

    The above method prints filenames with progressively newer access time and the last file it prints is the file with the latest access time.上述方法打印访问时间逐渐更新的文件名,并且它打印的最后一个文件是具有最新访问时间的文件。 You can obviously get the latest access time using a "tail -1".您显然可以使用“tail -1”获得最新的访问时间。

  2. You can have find recursively print the name and access time of all files in your subdirectory and then sort based on access time and the tail the biggest entry:您可以 find 递归打印子目录中所有文件的名称和访问时间,然后根据访问时间和尾部最大条目进行排序:

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

And there you have it...你有它...

I have this alias in my .profile that I use quite often:我经常使用的 .profile 中有这个别名:

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

So it does what you are looking for (with exception it doesn't traverse change date/time multiple levels) - looks for latest files (*.log and *.trc files in this case);所以它会做你正在寻找的东西(除了它不会遍历更改日期/时间多个级别) - 查找最新文件(在这种情况下为 *.log 和 *.trc 文件); also it only finds files modified in the last day, and then sorts by time and pipes the output through less :它也只查找在最后一天修改的文件,然后按时间排序并通过less管道输出:

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

PS.: Notice I don't have root on some of the servers, but always have sudo , so you may not need that part. PS.:请注意,我在某些服务器上没有 root 权限,但始终有sudo ,因此您可能不需要该部分。

This should actually do what the OP specifies:这实际上应该执行 OP 指定的操作:

One-liner in Bash: Bash 中的单行代码:

$ for first_level in `find . -maxdepth 1 -type d`; do find $first_level -printf "%TY-%Tm-%Td %TH:%TM:%TS $first_level\n" | sort -n | tail -n1 ; done

which gives output such as:它给出了输出,例如:

2020-09-12 10:50:43.9881728000 .
2020-08-23 14:47:55.3828912000 ./.cache
2018-10-18 10:48:57.5483235000 ./.config
2019-09-20 16:46:38.0803415000 ./.emacs.d
2020-08-23 14:48:19.6171696000 ./.local
2020-08-23 14:24:17.9773605000 ./.nano

This lists each first-level directory with the human-readable timestamp of the latest file within those folders, even if it is in a subfolder, as requested in这列出了每个第一级目录以及这些文件夹中最新文件的人类可读时间戳,即使它位于子文件夹中,如

"I need to make a list of all these directories that is constructed in a way such that every first-level directory is listed next to the date and time of the latest created/modified file within it." “我需要列出所有这些目录,这些目录的构建方式使得每个一级目录都列在其中最新创建/修改文件的日期和时间旁边。”

@anubhava's answer is great, but unfortunately won't work on BSD tools – ie it won't work with the find that comes installed by default on macOS , because BSD find doesn't have the -printf operator. @anubhava 的答案很棒,但不幸的是不适用于 BSD 工具 - 即它不适用于默认安装在 macOS find的 find ,因为 BSD find没有-printf运算符。

So here's a variation that works with macOS + BSD (tested on my Catalina Mac), which combines BSD find with xargs and stat :所以这是一个适用于 macOS + BSD 的变体(在我的 Catalina Mac 上测试过),它结合了 BSD findxargsstat

$ find . -type f -print0 \
      | xargs -0 -n1 -I{} stat -f '%Fm %N' "{}" \
      | sort -rn 

While I'm here, here's BSD command sequence I like to use, which puts the timestamp in ISO-8601 format当我在这里时,这是我喜欢使用的 BSD 命令序列,它将时间戳设置为ISO-8601 格式

$ find . -type f -print0 \
    | xargs -0 -n1 -I{} \
       stat  -f '%Sm %N' -t '%Y-%m-%d %H:%M:%S' "{}" \
    | sort -rn

(note that both my answers, unlike @anubhava's, pass the filenames from find to xargs as a single argument rather than a \0 terminated list, which changes what gets piped out at the very end) (请注意,与@anubhava 不同,我的两个答案都将文件名从find传递给xargs作为单个参数而不是\0终止列表,这会改变最后通过管道输出的内容)

And here's the GNU version (ie @anubhava's answer, but in iso-8601 format):这是 GNU 版本(即@anubhava 的答案,但采用 iso-8601 格式):

$ gfind . -type f -printf "%T+ %p\0" | sort -zk1nr

Related q: find lacks the option -printf, now what?相关问: find 缺少选项-printf,现在怎么办?

Quick Bash function:快速打击功能:

# 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"
}

Find the latest modified file in a directory:在目录中查找最新修改的文​​件:

findLatestModifiedFiles "/home/jason/" 1

You can also specify your own date/time format as the third argument.您还可以指定您自己的日期/时间格式作为第三个参数。

The following returns you a string of the timestamp and the name of the file with the most recent timestamp:下面将返回一个时间戳字符串和具有最新时间戳的文件的名称:

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

Resulting in an output of the form: <yy-mm-dd-hh-mm-ss.nanosec> <filename>产生以下形式的输出: <yy-mm-dd-hh-mm-ss.nanosec> <filename>

For those, who faced对于那些面临

stat: unrecognized option: format

when executed the line from Heppo's answer ( find $1 -type f -exec stat --format '%Y :%y %n' "{}" \; | sort -nr | cut -d: -f2- | head )当执行Heppo 答案中的行时( find $1 -type f -exec stat --format '%Y :%y %n' "{}" \; | sort -nr | cut -d: -f2- | head

Please try the -c key to replace --format and finally the call will be:请尝试使用-c键替换--format最终调用将是:

find $1 -type f -exec stat -c '%Y :%y %n' "{}" \; | sort -nr | cut -d: -f2- | head

That worked for me inside of some Docker containers, where stat was not able to use --format option.这在一些 Docker 容器中对我有用,其中stat无法使用--format选项。

This could be done with a recursive function in Bash too.这也可以通过 Bash 中的递归函数来完成。

Let F be a function that displays the time of file which must be lexicographically sortable yyyy-mm-dd, etc., (OS-dependent?)让 F 是一个函数,它显示文件的时间,该文件必须是按字典顺序排序的 yyyy-mm-dd 等,(取决于操作系统?)

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

R, the recursive function that runs through directories: R,遍历目录的递归函数:

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

And finally最后

for f in *;do [ -d "$f" ]&&echo `R "$f"|sort|tail -1`" $f";done

You may give the printf ACTION of find a try你可以试试 find 的 printf ACTION

%Ak File's last access time in the format specified by k, which is either @' or a directive for the C strftime' function. %Ak 文件的最后访问时间,格式由 k 指定,可以是@' or a directive for the C The possible values for k are listed below;下面列出了 k 的可能值; some of them might not be available on all systems, due to differences in `strftime' between systems.由于系统之间的“strftime”不同,其中一些可能并非在所有系统上都可用。

Please find the details in @anubhava's answer请在@anubhava 的答案中找到详细信息

On mac I use this在 mac 我用这个

find . -type f -exec stat -f "%m %N" "{}" \; | sort -nr | perl -n -e '@a = split / /;print `ls -l $a[1]`' | vim -

if you want filter some files you can use grep with regexp ie如果你想过滤一些文件,你可以使用 grep 和正则表达式,即

find . -type f -exec stat -f "%m %N" "{}" \; | sort -nr | grep -v -E \.class$ | perl -n -e '@a = split / /;print `ls -l $a[1]`' | vim -

Bash has one-liner-script solution for, how to recursively find latest modified files in multiple directories. Bash 有一个单行脚本解决方案,用于如何递归地在多个目录中查找最新修改的文​​件。 kindly find below command with your target directories.请在您的目标目录中找到以下命令。

 ls -ltr $(find /path/dir1 /path/dir2 -type f)

and for today, grep today date or time as mentioned in below command对于今天,grep 今天的日期或时间,如下面的命令中所述

 (ls -ltr $(find /path/dir1 /path/dir2 -type f)) |grep -i 'Oct 24'

For plain ls output, use this.对于普通的ls输出,使用它。 There is no argument list, so it can't get too long:没有参数列表,所以不能太长:

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

And niceified with cut for just the dates, times, and name:并用cut修饰日期、时间和名称:

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

EDIT : Just noticed that the current top answer sorts by modification date.编辑:刚刚注意到当前的最佳答案按修改日期排序。 That's just as easy with the second example here, since the modification date is first on each line - slap a sort onto the end:这与这里的第二个示例一样简单,因为修改日期是每行的第一个 - 在末尾添加一个排序:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何找到目录中最新修改文件的时间戳(递归)? - How to find the timestamp of the latest modified file in a directory (recursively)? 递归查找子目录和文件 - Recursively find subdirectories and files 如何在列表中查找包含使用部分名称的目录和子目录中的所有文件,然后将它们复制到新文件夹 - How to find all files in a directory and subdirectories that contain using partial names within a list then copy them to a new folder 如何在Linux中递归重命名目录和子目录? - How to rename directory and subdirectories recursively in linux? 递归查找目录中的文件数 - Recursively find the number of files in a directory 如何在文件列表中检查字符串并在Linux中显示最新修改的字符串 - How to check a string in a list of files and display the latest modified one in Linux 如何编写bash脚本以递归方式扫描子目录并列出当前月份的文件? - How to write bash script which recursively scan subdirectories and list files with current day of month? 如何按文件类型递归查找文件并将它们复制到目录? - How to find files recursively by file type and copy them to a directory? 如何列出(ls)目录中最后修改的 5 个文件? - How can I list (ls) the 5 last modified files in a directory? 如何计算父目录的特定子目录中的文件? - How to count files in specific subdirectories of a parent directory?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM