列出/打印每个目录中最旧和最新的文件

列出/打印每个目录中最旧和最新的文件

需要一些帮助,大家。

我需要为每个 unix 目录中最旧和最新的文件生成一份报告

结构简单

主文件夹具有多个子文件夹,每个子文件夹包含多个文件。

Folder
-Subfolders
--files

下面应输出到具有以下格式的 txt 文件。

SUBFOLDER_X
 OLDEST:Date:filename
 NEWEST:Date:filename
SUBFOLDER_Y
 OLDEST:Date:filename
 NEWEST:Date:filename

等等...

我尝试了下面的内容但坚持将其变成报告的形式。


find . -maxdepth 1 -type f | cut -c3- |xargs ls -t | head -1

任何帮助将非常感激。

谢谢

答案1

你使用了find -maxdepth 1。我假设这是 GNU find,并且你的操作系统中的其他工具也支持 GNU 扩展。这个答案使用 GNU find、 GNUsort和 GNU sed;它是不是便携的。

以下代码旨在可靠地处理所有文件名(包括带换行符的文件名)。数据被处理为以空字符结尾的字符串,直到最终tr将空字符转换为换行符,因此输出在终端中看起来不错¹。转换后,输出可能会产生歧义(因为文件名中有换行符),但在转换之前则不会:每个以空字符结尾的行要么以 开头./(然后您就知道这是您的SUBFOLDER_*行)要么以OLDEST:/开头NEWEST:。如果您想进一步解析输出,请先进行解析tr,并记住您正在处理以空字符结尾的行。

cd Folder进而:

#!/bin/sh

for d in ./*/; do
( cd "$d" && {
  printf '%s\0' "$d"
  find . -maxdepth 1 -type f -printf '%T@ %TF:%P\0' \
  | sort -zn | sed -z '1 p' | sed -zn '
    1 {s/[^ ]* / OLDEST:/;p}
    $ {s/[^ ]* / NEWEST:/;p}
  '; }
)
done | tr '\0' '\n'

笔记:

  • shebang#!/bin/sh表示 shell 代码是可移植的。我指的是 shell 代码本身,这些工具确实使用了不可移植的扩展。您不需要将代码作为脚本运行,也不需要严格地在 中运行它sh,您可以将其粘贴到交互式 POSIX 兼容 shell(例如 Bash)中。

  • 我们使用子shell(( )),因此的范围cd是有限的。

  • 尾随/意味着for d in ./*/我们正在迭代目录(以及目录的符号链接)。

  • 请记住*不匹配以点开头的名称。我们的代码会忽略隐藏目录。在使用之前.*(如果您想要隐藏目录),请注意它将匹配...

  • ./for d in ./*/两个原因:

    1. 我们不需要--稍后cd "$d"(更多信息:以破折号开头的文件名)。
    2. 如果子目录名为OLDEST:…,它将显示为./ OLDEST:…,您将能够分辨出它是一行SUBFOLDER_*。如果没有 ,./行可能看起来像是真正的OLDEST:行,除非您引入明确的前缀(例如printf 'DIR:%s\0' "$d")。
  • find“我使用是-type f因为您使用了它”中,我根据 POSIX 中“文件”的含义阅读了短语“最旧和最新的文件”(在标题中)广泛。看来您只想要常规文件。

  • 请注意,我们对子目录的循环包括目录的符号链接,但-type f不匹配常规文件的符号链接。虽然./*/忽略了隐藏目录,find但不会忽略隐藏文件。

  • 因为find我使用了-maxdepth 1,所以你也使用了。-type f这意味着子目录(如果有)及其内容将被完全忽略,就像它们不存在一样。

  • 调整%TF满足您的需求。

  • 没有常规文件的目录将显示为一行,下面./…没有OLDEST:/NEWEST:行。

  • 会出现一个只包含一个常规文件的目录,其中文件同时列为OLDEST:NEWEST:。为了使这种情况有效,我们需要从 复制第一行find,这就是sed -z '1 p'所做的(如果有更多行,那么这sed最终将无关紧要)。


¹ 但输出并未经过净化。你的终端可能仍会拦截并响应转义序列、铃声字符或任何配置为对其作出反应的内容(如果此类序列或字符出现在文件名中)。要安全地查看输出,请将其通过管道传输到分页器,如less

相关内容