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

2024-10-21 09:14:00
admin
原创
230
摘要:问题描述:操作系统: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 的回答中的详细信息

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用