这两种解决方案都有效,并通过本文中的复制粘贴进行了测试。
第一个相当慢。一个问题是循环内的外部程序调用 - 例如,date 会为 每个 文件调用。您可以通过不在输出数组中包含日期来加快速度(请参阅下面的注释)。特别是对于方法 2 - 这将导致 while 循环内没有 external 命令调用。但方法 1 确实存在问题 - 速度要慢几个数量级。
另外,有人可能知道如何将纪元日期转换为 awk 中的另一种格式,这可能会更快。也许你也可以在awk 中进行排序。也许只是保持纪元日期?
这些解决方案是 bash / GNU 重的,不能移植到其他环境(这里是 bash 字符串,find-printf)。 OP 标记为 linux 和 bash,因此可以假定为 GNU。
解决方案 1 - 捕获 任何 压缩文件 - 使用 file 匹配(慢)
- “压缩”的标准是
file 输出是否包含单词compress
- 足够可靠,但可能与其他文件类型描述有冲突?
-
file -l | grep compress(文件 5.38,Ubuntu 20.04,WSL)对我来说根本没有冲突(列出的所有文件都是压缩格式)
- 除此之外,我找不到对任何压缩文件进行分类的方法
- 我在一个包含 1664 个文件的目录上运行了这个 - 时间(实际)是 40 秒
#!/bin/bash
# Capture all files, recursively, in $TARGET, that are
# compressed files. In an indexed array. Using file name
# extensions to match.
# Initialise variables, and check the target is valid
declare -g c= compressed_files= path= TARGET=$1
[[ -r "$TARGET" ]] || exit 1
# Make the array
# A here string (<<<) must be used, to keep array in the global environment
while IFS= read -r -d '' path; do
[[ "$(file --brief "${path%% *}")" == *compress* ]] &&
compressed_files[c++]="${path% *} $(date -d @${path##* })"
done < \
<(
find "$TARGET" -type f -printf '%p %s %T@\0' |
awk '{$2 = ($2 / 1024); print}' |
sort -n -k 3
)
# Print results - to test
printf '%s\n' "${compressed_files[@]}"
解决方案 2 - 使用 文件扩展名 - 速度提高几个数量级
-
如果您确切知道要查找的扩展程序,您可以
将它们组合成 find 命令
-
这很多更快
-
在与上述相同的目录中,包含 1664 个文件 - 时间(实际)为 200 毫秒
-
此示例查找 .gz、.zip 和 .7z(分别为 gzip、zip 和 7zip)
-
我不确定-type f -and -regex '.*[.]\(gz\|zip\|7z\) -and printf 是否会再次更快,现在我想起来了。我从 glob 开始,因为我认为这更快
-
这也可能允许将扩展列表存储在变量中..
-
此方法可避免对目标中的每个文件进行file分析
-
它还使 while 循环更短 - 你只是在迭代 匹配
-
注意这里-printf的重复,这是由于逻辑
查找用途:-printf 是“真”。如果单独包含它,它会
充当“匹配”并打印所有文件
-
它必须用作名称匹配为真的结果(使用-and)
-
也许有人有更好的作文?
#!/bin/bash
# Capture all files, recursively, in $TARGET, that are
# compressed files. In an indexed array. Using file name
# extensions to match.
# Initialise variables, and check the target is valid
declare -g c= compressed_files= path= TARGET=$1
[[ -r "$TARGET" ]] || exit 1
while IFS= read -r -d '' path; do
compressed_files[c++]="${path% *} $(date -d @${path##* })"
done < \
<(
find "$TARGET" \
-type f -and -name '*.gz' -and -printf '%p %s %T@\0' -or \
-type f -and -name '*.zip' -and -printf '%p %s %T@\0' -or \
-type f -and -name '*.7z' -and -printf '%p %s %T@\0' |
awk '{$2 = ($2 / 1024); print}' |
sort -n -k 3
)
# Print results - for testing
printf '%s\n' "${compressed_files[@]}"
样本输出(任一方法):
$ comp-find.bash /tmp
/tmp/comptest/websters_english_dictionary.tmp.tar.gz 265.148 Thu Sep 10 07:53:37 AEST 2020
/tmp/comptest/What_is_Systems_Architecture_PART_1.tar.gz 1357.06 Thu Sep 10 08:17:47 AEST 2020
注意:
-
您可以添加文字K 来指示块大小/单位(千字节)
-
如果你想只打印这个数组的路径,你可以使用后缀去除:printf '%s\n' "${files[@]&& *}"
-
对于数组中没有日期(它用于排序,但它的工作可能完成),只需删除 $(date -d @${path##* })(包括空格)。
-
有点切线,但要使用不同的日期格式,请将$(date -d @${path##* }) 替换为:
$(date -I -d @${path##* }) ISO 格式 - 请注意短选择样式:date -Id @[date] 对我不起作用
$(date -d @${path##* } +%Y-%M-%d_%H-%m-%S) 类似 ISO,但有秒数
$(date -d @${path##* } +%Y-%M-%d_%H-%m-%S) 再次相同,但有纳秒(find 给你纳秒)
抱歉,帖子太长了,希望能提供信息。