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

时间:2010-12-30 10:37:35

标签: bash filesystems find

似乎ls在进行递归调用时没有正确排序文件:

ls -altR . | head -n 3

如何在目录(包括子目录)中找到最近修改过的文件?

21 个答案:

答案 0 :(得分:333)

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一样,stat -c的使用率也是如此。虽然可以在BSD上执行相同的操作,但格式化的选项也不同(-f "%m %N"看起来不错)

我错过了复数的部分;如果你想要更多 最新文件,只需提高尾部参数。

答案 1 :(得分:119)

跟进@plundra's answer,这是BSD和OS X版本:

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

答案 2 :(得分:14)

您可以使用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。

答案 3 :(得分: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选项确保完整时间戳(格式年 - 月 - 日小时 - 分 - 秒 - 纳秒< / em>)被退回
  • awk '{ print $6," ",$7 }'仅提取日期和时间
  • awk '{ print $6," ",$7," ",$9 }'提取日期,时间和文件名
  • sort返回按日期排序的文件
  • tail -1仅返回上次修改的文件

答案 4 :(得分:9)

这似乎工作正常,即使是子目录:

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

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

答案 5 :(得分:6)

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

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替换为更高的数字

答案 6 :(得分:4)

这给出了一个排序列表:

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

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

答案 7 :(得分:3)

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

找到。 -type f -printf'%T @%p \ n'| sort -n -r |头-11 | cut -f2- -d“”| sed -e's,^。/ ,,'| xargs ls -U -l <​​/ strong>

这给出了一个完整的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。

答案 8 :(得分: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

这是一个递归函数,可以获取目录中最新修改的项目。如果此项目是目录,则递归调用该函数并搜索此目录等

答案 9 :(得分:2)

如果单独对每个文件运行stat要慢,可以使用xargs来加快速度:

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

答案 10 :(得分: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

答案 11 :(得分:2)

这个简单的cli也可以起作用:

ls -1t | head -1

您可以将-1更改为要列出的文件数

答案 12 :(得分:2)

我一直使用类似的东西,以及最近修改过的文件的前k列表。对于大型目录树,它可以快得多,以避免排序。对于最近修改过的前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.4s中的最新文件,与使用sort的25.5s解决方案相比,速度提高了7.5倍。

答案 13 :(得分:1)

我发现以下更短且具有更多可解释的输出:

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

答案 14 :(得分:1)

忽略隐藏文件 - 好看&amp;快速时间戳

$ 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跟随链接。

答案 15 :(得分:1)

以下命令适用于Solaris:

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

答案 16 :(得分:1)

我发现上面的命令很有用,但对于我的情况,我需要查看文件的日期和时间,以及我有几个名称中有空格的文件的问题。 这是我的工作解决方案。

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

答案 17 :(得分:0)

要搜索/ target_directory及其所有子目录中最近60分钟内已修改的文件:

$ find /target_directory -type f -mmin -60

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

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

答案 18 :(得分:0)

使用基于find的解决方案多年后,我发现自己希望能够排除诸如.git之类的目录。

我切换到了基于rsync的解决方案。将其放入~/bin/findlatest

#!/bin/sh
# Finds most recently modified files.
rsync -rL --list-only "$@" | grep -v '^d' | sort -k3,4r | head -5

现在findlatest .将列出5个最近修改的文件,而findlatest --exclude .git .将列出.git中5个除外的文件。

这是通过利用一些很少使用的rsync功能来实现的:“如果指定单个源arg [to rsync]而没有目标,则文件的输出格式类似于ls -l” < / em>(rsync手册页)。

采用rsync args的功能与基于rsync的备份工具结合使用非常有用。例如,我使用rsnapshot,并用rsnapshot.conf行备份应用程序目录:

backup  /var/atlassian/application-data/jira/current/   home    +rsync_long_args=--archive --filter="merge /opt/atlassian/jira/current/backups/rsync-excludes"

其中rsync-excludes列出了我不想备份的目录:

- log/
- logs/
- analytics-logs/
- tmp/
- monitor/*.rrd4j

我现在可以看到将使用以下文件备份的最新文件:

findlatest /var/atlassian/application-data/jira/current/ --filter="merge /opt/atlassian/jira/current/backups/rsync-excludes"

答案 19 :(得分:0)

我为这个问题写了一个pypi / github包,因为我也需要一个解决方案。

https://github.com/bucknerns/logtail

安装:

pip install logtail

用法:tails更改文件

logtail <log dir> [<glob match: default=*.log>]

用法2:在编辑器中打开最新更改的文件

editlatest <log dir> [<glob match: default=*.log>]

答案 20 :(得分:0)

我更喜欢这个,它更短:

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