按修改日期查找最新文件


38

如果要在包含子目录的(大)目录中找到最新文件(mtime),该怎么办?

我发现的许多帖子都提出了一些变化ls -lt | head(有趣的是,许多建议ls -ltr | tail都相同,但效率较低),除非您有子目录(我愿意),否则还可以。

再说一遍,你可以

find . -type f -exec ls -lt \{\} \+ | head

这肯定会解决一个命令可以指定的文件数量最多的问题,即,如果目录很大-exec...\+将发出单独的命令;因此,每个组将按其ls内部排序,但不超过整个集合。因此,负责人将获得第一批的最新条目。

有什么答案吗?


顺便说一句,您不需要所有这些反斜杠。
enzotib 2011年

@enzotib:您(\ +),否则得到find: missing argument to '-exec'
安排

@arrange:我没有此错误,因为它对+没有意义bash,所以无需转义。
enzotib

@enzotib:您是对的,我的错,对不起
安排

Answers:


46

您无需再使用外部命令(如ls),因为find可以通过-printf操作完成所有您需要的操作:

find /path -printf '%T+ %p\n' | sort -r | head

1
是的,我想出了,find . -type f -exec stat --format=%y \{\} \+ | sort -r | head -n1但是您的解决方案要干净得多!
Rich

3
追加| cut -d ' ' -f2仅获取文件名
qwr

您也可以剔除输出head以包括一定数量的行。我只需要第一行,所以我使用了head -n 1
Timmah

8

今天我也遇到了类似的问题,但是我没有进行攻击find。我需要一些可以让我ssh返回主目录中最新编辑文件的文件。这大概是我想出的:

ls -tp | grep -v /$ | head -1

向目录添加尾部斜杠,删除以斜杠结尾的行的-p选项(又名所有目录),并将输出限制为单个文件。lsgrep -vhead -1

find如果要返回的只是文件名,那么这比使用繁琐得多。


这不处理子目录。
克莱门特

4

这在我的系统上比快printf,尽管我不明白为什么

find /path -type f -exec stat -c "%y %n" {} + | sort -r | head

我确认,速度更快。
enzotib 2011年

还有一点,... | sort -r | head -n1 | cut -d " " -f 4-如果您只想获取文件名。
林果皞2016年

我只是发现sort -r如果跨多行的文件名存在将是错误的。
林果皞2016年

2

编辑:我想这篇文章并不是像我认为的那样“不是特别有用”。这是一个非常快速的解决方案,它只跟踪最新修改的文​​件(而不是对整个文件列表进行排序):

find . -type f -printf '%T@ %p\n' | awk 'BEGIN { mostrecenttime = 0; mostrecentline = "nothing"; } { if ($1 > mostrecenttime) { mostrecenttime = $1; mostrecentline = $0; } } END { print mostrecentline; }' | cut -f2- -d ' '

为了清楚起见,将其分布在多行中,如下所示:

find . -type f -printf '%T@ %p\n' | awk '
    BEGIN { mostrecenttime = 0; mostrecentline = "nothing"; }
    {
        if ($1 > mostrecenttime)
            { mostrecenttime = $1; mostrecentline = $0; }
    }
    END { print mostrecentline; }' | cut -f2- -d ' '

编辑结束


这不是一个特别有用的帖子,但是由于“安排”是在讨论速度,我想我应该分享一下。

range和enzotib的解决方案包括将目录中的所有文件及其mtime列出,然后进行排序。如您所知,排序并不需要找到最大值。查找最大值可以在线性时间内完成,但排序需要n log(n)个时间[我知道相差不大,但仍然;)]。我想不出一个整齐的实现方法。[编辑:上面提供的一种简洁(尽管看上去很脏)和快速实现。]

第二件事-若要在目录中找到最新编辑的文件,请在每个1级子目录中递归地找到最新编辑的文件。让此文件代表子目录。现在,对1级文件以及1级子目录的代表进行排序。如果每个目录的1级文件和子目录的数量几乎是恒定的,则此过程应与文件总数成线性比例。

这是我想实现此目的的方法:

findrecent() { { find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1; }
findrecent .

我跑了这个,发现了很多find: findrecent: No such file or directory错误。原因:-exec的find在另一个shell中运行。我尝试在.bashrc,.xsessionrc中定义findrecent,但这些方法无济于事[感谢您的帮助]。最后我求助于

#!/bin/bash
{ find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1;

findrecent我的PATH中调用的脚本中,然后运行它。

我跑了这个,一直在等待,没有输出。为了确保我没有处理任何无限循环,我将文件修改为

#!/bin/bash
echo "$1" >&2
{ find "$1" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -1 && find "$1" -mindepth 1 -maxdepth 1 -type d -exec findrecent {} \;; } | sort -r | head -1;

然后再试一次。它确实有效-但是在我的家用文件夹上花费了1分35秒-安排和恩佐替布的解决方案分别花费了1.69和1.95秒!

O(n)优于O(n log(n))的优势!该死的函数调用开销![或者更确切地说,脚本调用的开销]

但是此脚本的扩展性比早期解决方案要好,我敢打赌它在Google的存储库上的运行速度将比它们快;


2

使用perl与conjonctin find

 find my_directory -type f -printf '%T@\t%p\n' | perl -ane '@m=@F if ($F[0]>$m[0]); END{print $m[1];}'

您将获得具有最大历元==最后修改文件的文件名。


1

它并不那么时尚,但是也可以使用Midnight Commander来实现:搜索*,将结果面板化,以相反的时间按修改时间排序。

显然,这要慢一些find-我的主目录包含922000个文件,在不到mc14分钟的时间内进行find了排序,而花了不到5 分钟的时间-但有一些好处:

  • 我可能花了9分钟的时间才发明一个适当的find调用:)

  • 发生错误的机会更少(忘记为排序等指定-r。-重新开始)

  • 可以通过更改排序顺序等来处理结果集。-无需重新查询文件。

  • 可能只对结果集中的某些文件执行文件操作-即按大小排序,删除一些不需要的大文件

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.