【问题标题】:Get most recent file in a directory on Linux在 Linux 上的目录中获取最新文件
【发布时间】:2010-11-04 04:19:26
【问题描述】:

寻找将返回目录中单个最新文件的命令。

没有看到ls的限制参数...

【问题讨论】:

标签: linux shell command-line


【解决方案1】:
ls -Art | tail -n 1

不是很优雅,但很有效。

使用的标志:

-A 列出除... 之外的所有文件

-r 排序时倒序

-t 按时间排序,最新的在前

【讨论】:

  • 使用 ls -Artls 还可以查看文件日期。
  • 一个小问题:此版本将ls 的所有输出通过管道传输到tail,然后仅打印最后一行。恕我直言,最好按升序排序并改用head,正如chaos 建议的那样。打印第一行后,head 退出,因此发送下一行(实际上是下一个块)将上升一个 SIGPIPE,ls 也将退出。
  • @TrueY 我非常同意。 Chaos 的答案更有效率。
  • 请注意,此解决方案包括目录和文件。这可能是好事也可能是坏事;这取决于个人用户想要什么。我提出这个问题的原因是最初的问题是“文件”。
  • 我认为使用 tail 代替 head 的预期好处可能是排除包含描述由 ls 返回的总数的行。
【解决方案2】:
ls -t | head -n1

这个命令实际上给出了当前工作目录中最新修改的文​​件。

【讨论】:

  • 相当于我的,而且可能更高效。
  • @Josir 这可以修改为包含带有ls -tl | head -n 1 的日期戳,并且它不必像我的那样将整个表推入管道。
  • @noɥʇʎԀʎzɐɹƆ ls -t *.png | head -n1
  • 如果它是最新修改的,则返回一个文件夹,如果您特别想要最新修改的文​​件,请使用:ls -Art | head -n1
  • @achasinh 将head 替换为tail。理想情况下还包括--group-directories-first
【解决方案3】:

这是一个递归版本(即它在某个目录或其任何子目录中找到最近更新的文件)

find /dir/path -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 2- | tail -n 1

命令行的简单外行解释:

  • find /dir/path -type f 查找目录下的所有文件
    • -printf "%T@ %p\n" 为每个文件打印一行,其中 %T@ 是自 1970 纪元以来的浮点秒数,%p 是文件名路径,\n 是换行符
    • 更多信息见man find
  • | 是一个外壳 @9​​87654329@(参见 man bash 部分的 Pipelines
  • sort -n 表示按第一列排序并将标记视为数字而不是字典(参见man sort
  • cut -d' ' -f 2- 表示使用 字符分割每一行,然后打印从第二个标记开始的所有标记(参见man cut
    • 注意:-f 2 只会打印第二个标记
  • tail -n 1 表示打印最后一行(见man tail

【讨论】:

  • 这是适用于 Mac 的解决方案:find $DIR -type f -exec stat -lt "%Y-%m-%d" {} \+ | cut -d' ' -f6- | sort -n | tail -1
  • 问题是 cut 命令用空格截断路径而不是 -f 2 使用 -f2- 将字段 2 返回到行尾
  • 如chaos的建议,如果你用sort -nr倒序排序,你可以用head -n 1代替tail -n 1,稍微提高效率。 (尽管如果您正在对递归查找进行排序,获取第一行或最后一行不会是缓慢的部分。)
  • 非常有用!我发现如果通过管道传输到 ls 会更友好:find ./ -type f -printf "%T@ %p\n" -ls | sort -n | cut -d' ' -f 2- | tail -n 1 | xargs -r ls -lah
  • @user 的 Mac 版本只排序/显示日期,而不是时间。这是一个固定版本:find $DIR -type f -exec stat -lt "%F %T" {} \+ | cut -d' ' -f6- | sort -n | tail -1
【解决方案4】:

关于可靠性的说明:

由于换行符与文件名中的任何字符一样有效,因此任何依赖 的解决方案(例如基于 head/tail 的解决方案都是有缺陷的。

对于 GNU ls,另一种选择是使用 --quoting-style=shell-always 选项和 bash 数组:

eval "files=($(ls -t --quoting-style=shell-always))"
((${#files[@]} > 0)) && printf '%s\n' "${files[0]}"

(如果您还想考虑隐藏文件,请将-A 选项添加到ls)。

如果您想限制常规文件(忽略目录、fifos、设备、符号链接、套接字...),您需要求助于 GNU find

使用 bash 4.4 或更新版本(readarray -d)和 GNU coreutils 8.25 或更新版本(cut -z):

readarray -t -d '' files < <(
  LC_ALL=C find . -maxdepth 1 -type f ! -name '.*' -printf '%T@/%f\0' |
  sort -rzn | cut -zd/ -f2)

((${#files[@]} > 0)) && printf '%s\n' "${files[0]}"

或递归:

readarray -t -d '' files < <(
  LC_ALL=C find . -name . -o -name '.*' -prune -o -type f -printf '%T@%p\0' |
  sort -rzn | cut -zd/ -f2-)

最好使用zsh 及其全局限定符而不是bash 来避免所有这些麻烦:

当前目录中最新的常规文件:

printf '%s\n' *(.om[1])

包括隐藏的:

printf '%s\n' *(D.om[1])

第二个最新:

printf '%s\n' *(.om[2])

符号链接解析后检查文件年龄:

printf '%s\n' *(-.om[1])

递归:

printf '%s\n' **/*(.om[1])

此外,启用补全系统(compinit 和 co)后,Ctrl+Xm 将成为扩展至最新文件的补全器。

所以:

vi Ctrl+Xm

会让你编辑最新的文件(你也有机会在按 Return 之前查看它)。

vi Alt+2Ctrl+Xm

对于第二个最新的文件。

vi *.cCtrl+Xm

获取最新的c 文件。

vi *(.)Ctrl+Xm

对于最新的常规文件(不是目录,也不是fifo/设备...),等等。

【讨论】:

  • 感谢zsh 的提示。您能否在 zsh docs 中提供更多详细信息的链接?
  • @freezed,见info zsh qualifiers
  • 谢谢@Stephane Chazelas
  • 我喜欢*(.om[1]),但我通常想在一组文件夹中找到最新的文件,即。 /path/to/folders*/*(.om[1]),不幸的是它只返回所有匹配文件夹中的最新文件。请参阅unix.stackexchange.com/questions/552103/…,了解如何在多个文件夹中完成它。
  • @SergioAraujo, c like find's -ctime 用于 inode 更改时间,与 creation无关> 时间。 mtime 可以看作是文件内容的创建时间(因为它们永远不会一次性创建)。一些系统和文件系统记录 birth*/*creation 时间,这是文件的 inode 产生(可能再次)存在的时间,但是没有可移植的 API 来检索它,并且 zsh 还没有相应的排序限定符。但是那个特定的时间并不是特别有用。见When was file created
【解决方案5】:

我用:

ls -ABrt1 --group-directories-first | tail -n1

它只给了我文件名,不包括文件夹。

【讨论】:

  • 除非目录只有目录
【解决方案6】:

ls -lAtr | tail -1

其他解决方案不包含以'.' 开头的文件。

此命令还将包括'.''..',这可能是也可能不是您想要的:

ls -latr | tail -1

【讨论】:

  • 这个会返回“。”如果目录的修改时间比包含的任何文件(比如删除)更晚?也许这是期望的行为,也许不是。但无论哪种方式你都是对的。
【解决方案7】:

在文件数量变得非常大(如整个文件系统)之前,查找/排序解决方案非常有效。使用 awk 来跟踪最新的文件:

find $DIR -type f -printf "%T@ %p\n" | 
awk '
BEGIN { recent = 0; file = "" }
{
if ($1 > recent)
   {
   recent = $1;
   file = $0;
   }
}
END { print file; }' |
sed 's/^[0-9]*\.[0-9]* //'

【讨论】:

  • 即使在大型目录或文件系统上,它也能非常快速准确地运行。非常优雅和高效的解决方案。谢谢!
【解决方案8】:

我喜欢echo *(om[1])zsh 语法),因为它只给出文件名,不调用任何其他命令。

【讨论】:

  • 如果您使用的是 zsh,则可以正常工作。你不使用zsh吗?我认为 bash 是 Ubuntu 中的默认设置;你可以安装 zsh,或者你可以找到一个等效的 bash 命令。
  • 命令为“echo”;它只是评估其参数并将它们发送到标准输出。在这种情况下,glob 限定符“om[1]”具有“o”,这意味着按照“m”对匹配文件进行排序,即修改时间。从该有序列表中,获取第一个文件 [1]。您可以阅读有关 glob 限定符的信息:zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Qualifiers
【解决方案9】:

根据 dmckee 的回答缩短变体:

ls -t | head -1

【讨论】:

  • 但是 -1 的 head 语法在很久以前就被弃用了,应该使用 -n 1
【解决方案10】:

如果您想获取最新更改的文件,还包括任何子目录,您可以使用这个小单行:

find . -type f -exec stat -c '%Y %n' {} \; | sort -nr | awk -v var="1" 'NR==1,NR==var {print $0}' | while read t f; do d=$(date -d @$t "+%b %d %T %Y"); echo "$d -- $f"; done

如果您不想对已更改的文件执行相同的操作,但对于访问的文件,您只需更改

%Y 参数从 stat 命令到 %X。您最近访问的文件的命令如下所示:

find . -type f -exec stat -c '%X %n' {} \; | sort -nr | awk -v var="1" 'NR==1,NR==var {print $0}' | while read t f; do d=$(date -d @$t "+%b %d %T %Y"); echo "$d -- $f"; done

对于这两个命令,如果您想列出多个文件,也可以更改 var="1" 参数。

【讨论】:

    【解决方案11】:

    我个人更喜欢尽可能少地使用非内置的bash 命令(以减少昂贵的 fork 和 exec 系统调用的数量)。要按日期排序,需要调用ls。但是使用head 并不是真的必要。我使用以下单行(仅适用于支持名称管道的系统):

    read newest < <(ls -t *.log)
    

    或获取最旧文件的名称

    read oldest < <(ls -rt *.log)
    

    (注意两个“

    如果还需要隐藏文件 - 可以添加 arg。

    我希望这会有所帮助。

    【讨论】:

    • 您应该说明文件名存储在 $oldest/newest var 中。但是对于最少数量的分叉 +1。
    • @squareatom 我认为 read 是内置的。但你是对的,也许不是。感谢您的评论!
    • 假设您知道内置是什么,您可能是正确的。但是,我只是在考虑OP的问题。他们要求一个可以返回某些东西的命令。从技术上讲,您的解决方案不会输出任何内容。所以只需在末尾添加“&& echo $newest”或类似的;-)
    【解决方案12】:

    使用 R 递归选项 .. 您可以在此处将其视为对良好答案的增强

    ls -arRtlh | tail -50
    

    【讨论】:

      【解决方案13】:

      只有 Bash 内置函数,紧跟 BashFAQ/003

      shopt -s nullglob
      
      for f in * .*; do
          [[ -d $f ]] && continue
          [[ $f -nt $latest ]] && latest=$f
      done
      
      printf '%s\n' "$latest"
      

      【讨论】:

        【解决方案14】:
        ls -t -1 | sed '1q'
        

        将显示文件夹中最后修改的项目。与grep 配对以查找带有关键字的最新条目

        ls -t -1 | grep foo | sed '1q'
        

        【讨论】:

        • 什么是'1q'? 1 是第一行相当于 head -n 1 什么是 q?
        【解决方案15】:

        试试这个简单的命令

        ls -ltq  <path>  | head -n 1
        

        如果你想要文件名 - 最后修改,路径 = /ab/cd/*.log

        如果您想要目录名称 - 最后修改,路径 = /ab/cd/*/

        【讨论】:

          【解决方案16】:

          递归:

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

          【讨论】:

            【解决方案17】:

            根据模式在每个目录中查找最新文件,例如名称以“tmp”结尾的工作目录的子目录(不区分大小写):

            find . -iname \*tmp -type d -exec sh -c "ls -lArt {} | tail -n 1" \;
            

            【讨论】:

              【解决方案18】:

              假设您不关心以. 开头的隐藏文件

              ls -rt | tail -n 1
              

              否则

              ls -Art | tail -n 1
              

              【讨论】:

                【解决方案19】:
                ls -Frt | grep "[^/]$" | tail -n 1
                

                【讨论】:

                • 还有其他答案提供了 OP 的问题,它们是多年前发布的。发布答案时,请确保添加新的解决方案或更好的解释,尤其是在回答较旧的问题时。
                • @help-info.de 请不要投票删除仅代码的答案。他们可能不是很好,但deletion is for things that are not answers
                • @Machavity - 我希望不要失败,只为迟到的答案发表评论。
                【解决方案20】:

                所有这些 ls/tail 解决方案对于 a 目录中的文件都可以正常工作 - 忽略子目录。

                为了在搜索中包含所有文件(递归),可以使用 find。 gioele 建议对格式化的查找输出进行排序。但要小心空格(他的建议不适用于空格)。

                这应该适用于所有文件名:

                find $DIR -type f -printf "%T@ %p\n" | sort -n | sed -r 's/^[0-9.]+\s+//' | tail -n 1 | xargs -I{} ls -l "{}"
                

                这是按 mtime 排序的,见 man find:

                %Ak    File's  last  access  time in the format specified by k, which is either `@' or a directive for the C `strftime' function.  The possible values for k are listed below; some of them might not be available on all systems, due to differences in `strftime' between systems.
                       @      seconds since Jan. 1, 1970, 00:00 GMT, with fractional part.
                %Ck    File's last status change time in the format specified by k, which is the same as for %A.
                %Tk    File's last modification time in the format specified by k, which is the same as for %A.
                

                所以只需将%T 替换为%C 即可按ctime 排序。

                【讨论】:

                • 您对@gioele 建议的空白问题是正确的,但您只需要在 -f 选项中添加一个连字符以使其成为修复该问题的范围:find $DIR -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 2- | tail -n 1 或者,保留除第一个字段外的所有字段:find $DIR -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 1 --complement | tail -n 1
                【解决方案21】:

                我也需要这样做,我找到了这些命令。这些对我有用:

                如果您希望最后一个文件在文件夹中的创建日期(访问时间):

                ls -Aru | tail -n 1  
                

                如果您希望最后一个文件的内容发生变化(修改时间):

                ls -Art | tail -n 1  
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-12-08
                  • 1970-01-01
                  • 2013-02-09
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2021-10-30
                  相关资源
                  最近更新 更多