如何逐行组合 `stat` 和 `md5sum` 输出?

How to combine `stat` and `md5sum` output line by line?

统计部分:

$ find * -depth -exec stat --format '%n %U %G' {} + | sort -d > acl_file
$ cat acl_file
xfce4/desktop/icons screen0-3824x1033.rc john john
Code/CachedData/f30a9b73e8ffc278e71575118b6bf568f04587c8/index-ec362010a4d520491a88088c200c853d.code john john
VirtualBox/selectorwindow.log.6 john john

$ 查找 * -depth -exec md5sum {} + |排序 -d > md5_file $猫md5_file

3da180c2d9d1104a17db0749d527aa4b  xfce4/desktop/icons screen0-3824x1033.rc
3de44d64a6ce81c63f9072c0517ed3b9  Code/CachedData/f30a9b73e8ffc278e71575118b6bf568f04587c8/index-ec362010a4d520491a88088c200c853d.code
3f85bb5b59bcd13b4fc63d5947e51294  VirtualBox/selectorwindow.log.6

如何将stat --format '%n %U %G'md5sum合并并逐行输出到文件,如:

3da180c2d9d1104a17db0749d527aa4b  xfce4/desktop/icons screen0-3824x1033.rc john john
3de44d64a6ce81c63f9072c0517ed3b9  Code/CachedData/f30a9b73e8ffc278e71575118b6bf568f04587c8/index-ec362010a4d520491a88088c200c853d.code john john
3f85bb5b59bcd13b4fc63d5947e51294  VirtualBox/selectorwindow.log.6 john john

最快的方法应该是:

find * -type f -exec stat --format '%n %U %G' "{}"  \; -exec md5sum "{}" \; |
{ while read -r line1 && read -r line2; do printf "%s %s\n" "${line2/ */}" "${line1}";done; } | 
sort -d

我们使用两个-exec逐个文件应用statmd5sum,然后我们读取两个输出行并使用printf逐个文件格式化一个输出行stat/md5sum 的输出。我们最终将整个输出通过管道传输到 sort.

警告: 当我们通过管道对整个输出进行排序时,您可能会等待所有 stat/md5sum 完成后才能在控制台上获得任何输出。 如果只有 md5sum 而不是 stat 在文件上失败(反之亦然),输出将被丢弃。

编辑: 输出更安全的方法:

find * -type f -exec md5sum "{}" \; -exec stat --format '%n %U %G' "{}"  \;  | 
{ while read -r line; do 
   mdsum="${line/[0-9a-f]*  /}"; 
   [ "${mdsum}" != "${line}" ] && 
      { mdsumdisp="${line%  ${mdsum}}"; mdsumfile="${mdsum}"; } || 
          { [ "${line#${mdsumfile}}" != "${line}" ] &&
             printf "%s %s\n" "${mdsumdisp}" "${line}"; }; 
   done; } |  sort -d

在这里,至少,我们检查我们在预期行上有类似 md5sum 的东西与行中的文件匹配。

这实际上只是@Zilog80 解决方案的一个小变体。我的时间测试通过在 git bash windows 笔记本电脑上的几百个文件 运行 的小型数据集上跳过 reads 快了几秒钟. YMMV.

mapfile -t lst< <( find . -type f -exec md5sum "{}" \; -exec stat --format '%U %G' "{}"  \; )
for ((i=0; i < ${#lst[@]}; i++)); do if (( i%2 )); then echo "${lst[i]}"; else printf "%s " "${lst[i]}"; fi done | sort -d

编辑

我原来的解决方案很糟糕。它会跳过隐藏子目录中的文件,并且 printf 会用空格破坏文件名。如果您没有要处理的隐藏目录,或者如果您 想要 跳过这些目录(例如,您正在 git 存储库中工作并且宁愿跳过 .git 树...),这里是返工。


shopt -s dotglob    # check hidden files 
shopt -s globstar   # process at arbitrary depth
for f in **/*; do   # this properly handles odd names
  [[ -f "$f" ]] && echo "$(md5sum "$f") $(stat --format "%U %G" "$f")"
done | sort -d