如何以递归方式查找并列出目录中最新修改的文件(包括子目录和时间)

2024-10-21 09:14:00
admin
原创
76
摘要:问题描述:操作系统:Linux文件系统类型:ext3首选解决方案:Bash(脚本/单行程序)、Ruby 或 Python我有多个目录,其中包含多个子目录和文件。我需要列出所有这些目录,列表的构建方式是,每个一级目录都列在其中最新创建/修改文件的日期和时间旁边。需要澄清的是,如果我修改了某个文件或修改了其在下一...

问题描述:

  • 操作系统:Linux

  • 文件系统类型:ext3

  • 首选解决方案:Bash(脚本/单行程序)、Ruby 或 Python

我有多个目录,其中包含多个子目录和文件。我需要列出所有这些目录,列表的构建方式是,每个一级目录都列在其中最新创建/修改文件的日期和时间旁边。

需要澄清的是,如果我修改了某个文件或修改了其在下一级子目录中的内容,则该时间戳应显示在第一级目录名称旁边。假设我有一个结构如下的目录:

./alfa/beta/gamma/example.txt

并且我修改了文件的内容example.txt,我需要以人类可读的形式(而不是纪元)显示在第一级目录旁边的时间alfa。我尝试使用 find、xargssort方法,但我无法解决在创建/修改几级以下的文件时“alfa”的文件系统时间戳不会改变的问题。


解决方案 1:

尝试一下这个:

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

这稍微快一点。

解决方案 2:

查找文件状态最后更改于N分钟之前的所有文件:

find -cmin -N

例如:

find -cmin -5

使用-ctime代替-cmin几天:

find -ctime -3

在 FreeBSD 和 MacOS 上:您还可以使用-ctime n[smhdw]秒、分钟、小时、天和周。如果没有提供单位,则默认为天。

例子:

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

解决方案 3:

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

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

解决方案 4:

我把Daniel Böhmer 的精彩回答简化为一句话:

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

如果文件名中有空格,可以使用此修改:

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

解决方案 5:

尝试一下:

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

它用于find从目录中收集所有文件,ls按修改日期排序列出它们,head选择第一个文件,最后stat以良好的格式显示时间。

目前,文件名中包含空格或其他特殊字符的文件并不安全。如果它还不能满足您的需求,请写一条评论。

解决方案 6:

这是我正在使用的(非常高效):

function find_last () { find "${1:-.}" -type f -printf '%TY-%Tm-%Td %TH:%TM %P
' 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

解决方案 7:

此命令适用于 Mac OS X:

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

在 Linux 上,正如原始海报所要求的那样,使用stat而不是gstat

当然,这个答案是user37078的杰出解决方案,从评论提升为完整答案。我结合了CharlesB的见解,以便gstat在 Mac OS X 上使用。顺便说一句,我从MacPorts而不是Homebrew获得了coreutils 。

以下是我将其打包成简单命令~/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' \n    |sort -nr |cut -d: -f2- |$H $N

解决方案 8:

忽略隐藏文件 — 带有快速准确的时间戳

以下是如何在包含子目录的目录中查找和列出最新修改的文​​件。隐藏文件会被故意忽略。而文件名中的空格处理得很好——但你不应该使用它们!时间格式可以自定义。

$ find . -type f -not -path '*/.*' -printf '%TY.%Tm.%Td %THh%TM %Ta %p
' |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

find点击链接即可找到更多内容。

解决方案 9:

这篇文章中的 Perl 和 Python 解决方案都帮助我在 Mac OS X 上解决了这个问题:

如何递归列出按修改日期排序的文件(没有可用的 stat 命令!)

引用该帖子:

Perl:

find . -type f -print |
perl -l -ne '
    $_{$_} = -M;  # store file age (mtime - now)
    END {
        $,="
";
        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'

解决方案 10:

这是一个适用于可能包含空格,换行符和 glob 字符的文件名的版本:

find . -type f -printf "%T@ %p" | sort -zk1nr
  • find ... -printf打印文件修改时间(Epoch 值),后跟空格和终止的文件名。

  • sort -zk1nr读取以 NUL 结尾的数据并按数字反向排序

由于问题带有 Linux 标签,我假设GNU Core Utilities可用。

您可以使用以下方式管道传输上述内容:

xargs -0 printf "%s
"

打印修改时间和按修改时间排序的文件名(最近的在前),以换行符结尾。

解决方案 11:

我显示的是最新访问时间,您可以轻松修改它以显示最新修改时间。

有两种方法可以做到这一点:


  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”获取最新访问时间。

  1. 您可以让 find 递归地打印子目录中所有文件的名称和访问时间,然后根据访问时间对尾部最大的条目进行排序:

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

就这样...

解决方案 12:

我的 .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

附言:请注意,我在某些服务器上没有 root 权限,但始终有sudo,因此您可能不需要那部分。

解决方案 13:

对于那些面临

stat: unrecognized option: format

当执行Heppo 的答案中的这一行时(find $1 -type f -exec stat --format '%Y :%y %n' "{}" ; | sort -nr | cut -d: -f2- | head

请尝试-c更换密钥--format,最终呼叫将是:

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

这对我来说在某些 Docker 容器内有效,但stat无法使用--format选项。

解决方案 14:

这实际上应该做 OP 指定的事情:

Bash 中的一行代码:

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

输出如下:

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

这将列出每个一级目录,并列出这些文件夹中最新文件的人性化时间戳,即使该文件位于子文件夹中,如

“我需要列出所有这些目录,并以这样的方式构建:每个一级目录都列在其中最新创建/修改的文件的日期和时间旁边。”

解决方案 15:

@anubhava 的回答很棒,但不幸的是它不适用于 BSD 工具 - 即它不适用于findmacOS 上默认安装的,因为 BSDfind没有-printf运算符。

因此,这里有一个适用于 macOS + BSD 的变体(在我的 Catalina Mac 上测试过),它将 BSD与findxargs结合在一起:stat

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

下面是我喜欢使用的 BSD 命令序列,它将时间戳设置为ISO-8601 格式

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

(请注意,与@anubhava 不同,我的两个答案都将文件名从作为单个参数传递,findxargs不是终止列表,这会改变最后输出的内容)

这是 GNU 版本(即@anubhava 的答案,但采用 iso-8601 格式):

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

相关问:find 缺少选项 -printf,现在怎么办?

解决方案 16:

Bash 有一个单行脚本解决方案,用于解决如何在多个目录中递归查找最新修改的文​​件。请在下面的命令中查找您的目标目录。

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

对于今天,使用 grep 今天的日期或时间,如下命令所示。

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

解决方案 17:

快速 Bash 功能:

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

查找目录中最新修改的文​​件:

findLatestModifiedFiles "/home/jason/" 1

您还可以指定自己的日期/时间格式作为第三个参数。

解决方案 18:

以下返回时间戳字符串和具有最新时间戳的文件的名称:

find $Directory -type f -printf "%TY-%Tm-%Td-%TH-%TM-%TS %p
" | sed -r 's/([[:digit:]]{2}).([[:digit:]]{2,})/-/' |     sort --field-separator='-' -nrk1 -nrk2 -nrk3 -nrk4 -nrk5 -nrk6 -nrk7 | head -n 1

产生如下形式的输出:
<yy-mm-dd-hh-mm-ss.nanosec> <filename>

解决方案 19:

对于纯文本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

编辑:刚刚注意到,当前的最佳答案按修改日期排序。这与这里的第二个示例一样简单,因为修改日期在每行的开头 - 将排序放在末尾:

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

解决方案 20:

这也可以通过 Bash 中的递归函数来完成。

让 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,遍历目录的递归函数:

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

解决方案 21:

在 Mac 上我用的是这个

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

如果你想过滤一些文件,你可以使用带有正则表达式的 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 -

解决方案 22:

您可以尝试 find 的 printf ACTION

%Ak 文件的最后访问时间,格式由 k 指定,可以是@' or a directive for the C strftime 函数。k 的可能值如下所示;由于不同系统之间的“strftime”不同,其中一些值可能并非在所有系统上都可用。

请参阅@anubhava 的回答中的详细信息

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用