你已经很接近了,只需要一些修复:
#!/bin/bash
find ./path/to/dir -type f -size +30000c -size -50000c -printf '%s %p\n' |
while read -r size filename; do
md5=$(md5sum "$filename" | awk '{print $1}')
printf "%-30s %s %10s\n" "$filename" "$md5" "$size"
done
产生类似的东西:
./CHECKSUM 36e371280a17372537a78167ce22b773 30400
./Makefile d21464a020be753a9d821cba58f046bc 40000
让我们从find 开始。我们可以通过-printf action 直接从find 获取文件名(路径)和大小。 %p 指定完整的文件名(相对路径)和%s 文件的大小。我们把%s放在第一位,所以read可以解析它,以防文件名包含空格。另外,我们只对文件感兴趣,所以我们将使用-type f 过滤器。
接下来,read 可以读取多个字段(以IFS 分隔,默认为空格、换行符和制表符)。如果字段多于给定的变量,则最后一个变量将保存所有剩余字段。此外,我们使用-r 来防止对输入中的转义字符进行(特殊)解释。对于读取的每一行(假设您的文件名不包含换行符),我们会使用您已经使用的命令计算 MD5 和。
最后,我们使用 shell 内置的printf 来格式化和打印所有字段。格式化 mini 语言类似于 C 的 printf:%-30s 表示左对齐的 30 个字符宽的字符串字段,例如。
奖励积分:处理带有换行符的文件名。 Unix 文件名可能不能包含的一个字符是 NULL (\0) 字符。虽然bash 不是特别擅长处理二进制(非文本)数据,但我们还是可以做到的:
#!/bin/bash
find ./path/to/dir -type f -size +30000c -size -50000c -printf '%s %p\0' |
while read -r -d '' size filename; do
md5=$(md5sum "$filename" | awk '{print $1}')
display_name=$(echo -n "$filename" | tr '\n' '?')
printf "%-30s %s %10s\n" "$display_name" "$md5" "$size"
done
首先,我们在-printf 中使用\0 来分隔记录find 输出,并匹配read -d ''。为了使文件名适合在一行中打印,我们必须将所有换行符\n 替换为(但仅用于显示)?。为此,我们可以使用tr,并结合echo -n(请注意,我们不能使用here-string <<<"$filename" 代替echo,因为here-string adds a trailing newline)。