如何在目录中递归地找到最新的修改文件?


Answers:


356
find . -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "

对于一棵大树,可能很难sort将所有内容都保留在内存中。

%T@为您提供修改时间,例如unix时间戳,进行sort -n数字排序,tail -1获取最后一行(最高时间戳),cut -f2 -d" "从输出中删除第一个字段(时间戳)。

编辑:正如-printf可能只有GNU一样,的ajreals用法stat -c也是如此。尽管可以在BSD上执行相同的操作,但是格式化选项有所不同(-f "%m %N"看来)

我错过了复数部分;如果您想要更多而不是最新文件,只需增加tail参数即可。


7
如果订单很重要,则可以将用途sort -rn | head -3改为sort -n | tail -3。一个版本将文件从最旧到最新,而另一个版本将文件从最新到最旧。
唐·福克纳

3
我有一个巨大的目录(大约一万个小文件),我担心性能,但是...此命令运行的时间不到一秒钟!很好,非常感谢!!!:-)
lucaferrario 2013年

2
“对于一棵大树,可能很难将所有内容保留在内存中。” sort/tmp根据需要在中创建临时文件(在中),因此我认为这不是问题。
弗拉基米尔·潘捷列夫2014年

1
修改为:-printf '%T@ %Tb %Td %TY %p\n'将给您一个日期戳(如果需要)(类似于ls
bshea

1
我发现以下内容更简短,输出结果也更可解释:find . -type f -printf '%TF %TT %p\n' | sort | tail -1
snth

129

跟随@plundra的答案,以下是BSD和OS X版本:

find . -type f -print0 | xargs -0 stat -f "%m %N" |
sort -rn | head -1 | cut -f2- -d" "

1
BSD / OS X是否find支持+而不是\;?因为那做同样的事情(作为参数传递多个文件),而没有-print0 | xargs -0管道。
DevSolar 2014年

如果我想获得降序修改的最后5个或n个文件,该怎么办?
khunshan

@khunshan更改head -1head -5
Emerson Farrugia

19

不用排序结果并只保留最后修改的结果,可以使用awk只打印修改时间最长的结果(以unix时间计):

find . -type f -printf "%T@\0%p\0" | awk '
    {
        if ($0>max) {
            max=$0; 
            getline mostrecent
        } else 
            getline
    } 
    END{print mostrecent}' RS='\0'

如果文件数量足够大,这应该是解决问题的较快方法。

我使用了NUL字符(即'\ 0'),因为从理论上讲,文件名可以包含任何字符(包括空格和换行符)。

如果您的系统中没有这样的病理文件名,则也可以使用换行符:

find . -type f -printf "%T@\n%p\n" | awk '
    {
        if ($0>max) {
            max=$0; 
            getline mostrecent
        } else 
            getline
    } 
    END{print mostrecent}' RS='\n'

此外,这也适用于mawk。


可以很容易地进行调整以保持三个最新状态。
暂停,直到另行通知。

1
这不适mawk用于Debian标准替代品。
2014年

不,但是在这种情况下,您可以使用换行符,如果它不会打扰您;)
marco 2014年

10

我很难在Solaris 10下找到最后修改的文件。find没有该printf选项,stat因此不可用。我发现以下适合我的解决方案:

find . -type f | sed 's/.*/"&"/' | xargs ls -E | awk '{ print $6," ",$7 }' | sort | tail -1

要同时显示文件名,请使用

find . -type f | sed 's/.*/"&"/' | xargs ls -E | awk '{ print $6," ",$7," ",$9 }' | sort | tail -1

说明

  • find . -type f 查找并列出所有文件
  • sed 's/.*/"&"/' 将路径名括在引号中以处理空格
  • xargs ls -E将加引号的路径发送到ls,该-E选项可确保返回完整的时间戳(格式为year-month-day hour-minute-seconds-nanoseconds
  • awk '{ print $6," ",$7 }' 仅提取日期和时间
  • awk '{ print $6," ",$7," ",$9 }' 提取日期,时间和文件名
  • sort 返回按日期排序的文件
  • tail -1 仅返回最后修改的文件

9

即使使用子目录,这似乎也可以正常工作:

find . -type f | xargs ls -ltr | tail -n 1

如果文件太多,请优化查找。


1
-l选项ls似乎没有必要。只是-tr似乎足够了。
Acumenus

6
这似乎是按目录排序的,因此不一定会显示最新文件
Fabian Schmengler 2015年

1
如果文件路径中有空格,最好执行以下操作:find . -type f -print0 | xargs -0 ls -ltr | tail -n 1
定期维护,

找不到适合我的最新文件。
K.-Michael Aye

1
如果文件名中有空格,则认为这会中断
晶圆厚度

7

显示带有人类可读时间戳的最新文件:

find . -type f -printf '%TY-%Tm-%Td %TH:%TM: %Tz %p\n'| sort -n | tail -n1

结果如下:

2015-10-06 11:30: +0200 ./foo/bar.txt

要显示更多文件,请替换-n1为更大的数字


5

我一直都在使用类似的东西,以及最近修改过的文件的前k个列表。对于大型目录树,避免sort可能会更快。对于仅top-1最近修改的文件:

find . -type f -printf '%T@ %p\n' | perl -ne '@a=split(/\s+/, $_, 2); ($t,$f)=@a if $a[0]>$t; print $f if eof()'

在包含170万个文件的目录上,我得到的最新数据为3.4秒,使用sort的25.5s解决方案的速度提高了7.5倍。


非常酷:我刚刚用eof()交换了system(“ ls -l $ f”)的最后一个打印内容,以一种很好的方式查看日期。
Martin T.

@MartinT。:太好了,不客气。我很奇怪,当O(n)方法可用时,人们有这种对事物进行排序的本能(O(n log n))。这似乎是避免排序的唯一答案。顺便说一句,我建议的命令的目的只是为了找到最新文件的路径。你可以在你的shell(例如,作为别名命令lastfile),然后你可以做任何你喜欢用的结果,如ls -l $(lastfile .),或open $(lastfile .)(在Mac)等
皮埃尔·d

哦,我的立场是正确的:我在下面看到了另一个答案(@marco)。+1。
Pierre D

4

这给出了一个排序列表:

find . -type f -ls 2>/dev/null | sort -M -k8,10 | head -n5

通过在排序命令中放置“ -r”来颠倒顺序。如果只需要文件名,请插入“ awk'{print $ 11}'|” 在“ |”之前 头'


3

在Ubuntu 13上,它可以做到以下几点,可能会更快一些,因为它可以反转排序并使用“ head”而不是“ tail”,从而减少了工作量。要在树中显示11个最新文件:

找 。类型的f -printf'%T @%p \ n'| 排序-n -r | 头-11 | 切-f2- -d“” | sed -e's,^。/ ,, | | xargs ls -U -l

这样就给出了完整的ls列表,而无需重新排序,并且省略了“查找”放在每个文件名上的烦人的“ ./”。

或者,作为bash函数:

treecent () {
  local numl
  if [[ 0 -eq $# ]] ; then
    numl=11   # Or whatever default you want.
  else
    numl=$1
  fi
  find . -type f -printf '%T@ %p\n' | sort -n -r | head -${numl} |  cut -f2- -d" " | sed -e 's,^\./,,' | xargs ls -U -l
}

尽管如此,大部分工作还是由plundra的原始解决方案完成的。谢谢plundra。


3

我遇到了同样的问题。我需要递归查找最新文件。查找花费了大约50分钟的时间。

这是一个小脚本,可以更快地执行此操作:

#!/bin/sh

CURRENT_DIR='.'

zob () {
    FILE=$(ls -Art1 ${CURRENT_DIR} | tail -n 1)
    if [ ! -f ${FILE} ]; then
        CURRENT_DIR="${CURRENT_DIR}/${FILE}"
        zob
    fi
    echo $FILE
    exit
}
zob

这是一个递归函数,它获取目录的最新修改项。如果此项目是目录,则该函数将递归调用并搜索到该目录,依此类推。


3

我发现以下内容简短且输出可解释:

find . -type f -printf '%TF %TT %p\n' | sort | tail -1

给定标准化ISO格式日期时间的固定长度,按字典顺序排序是可以的,我们不需要-n排序选项。

如果要再次删除时间戳记,可以使用:

find . -type f -printf '%TFT%TT %p\n' | sort | tail -1 | cut -f2- -d' '


2

这会将当前目录中所有目录的修改时间递归更改为每个目录中的最新文件:

for dir in */; do find $dir -type f -printf '%T@ "%p"\n' | sort -n | tail -1 | cut -f2- -d" " | xargs -I {} touch -r {} $dir; done

1
如果任何目录包含空格,它会严重中断-需要设置IFS并使用引号:IFS = $'\ n';对于$(find ./ -type d)中的目录;做echo“ $ dir”; 查找“ $ dir”-类型f -printf'%T @“%p” \ n'| 排序-n | 尾巴-1 | 切-f2- -d“” | xargs -I {} touch -r {}“ $ dir”; 完成
安迪·李·罗宾逊


1

我发现上面的命令很有用,但就我而言,我还需要查看文件的日期和时间,并且几个名称中带有空格的文件也存在问题。这是我的工作解决方案。

find . -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" " | sed 's/.*/"&"/' | xargs ls -l

1

以下命令在Solaris上有效:

find . -name "*zip" -type f | xargs ls -ltr | tail -1 

1

忽略隐藏文件-精美而快速的时间戳记

$ 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

更多

更多的 find关注链接。


1

要搜索/ target_directory及其所有子目录中最近60分钟内已修改的文件,请执行以下操作:

$ find /target_directory -type f -mmin -60

要查找最新修改的文​​件,请按照相反的更新时间顺序进行排序(即,首先将最新更新的文件排在第一位):

$ find /etc -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort -r

0

我喜欢这个,它更短:

find . -type f -print0|xargs -0 ls -drt|tail -n 1

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.