需要一些帮助,大家。
我需要为每个 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 ./*/
两个原因:- 我们不需要
--
稍后cd "$d"
(更多信息:以破折号开头的文件名)。 - 如果子目录名为
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
。