等待 md5sum 命令完成

等待 md5sum 命令完成
#!/bin/bash

cd /path-to-directory
md5=$(find . -type f -exec md5sum {} \; | sort -k 2 | md5sum)

zenity --info \
--title= "Calculated checksum" \
--text= "$md5"

目录的递归校验和计算过程需要一段时间。 bash 脚本不会等到该过程完成,它只是移动到下一个命令,即显示计算出的校验和的对话框。因此对话框显示错误的校验和。

是否有一个选项可以告诉脚本等待校验和的计算完成?此外,是否有一个选项可以将校验和计算的进度通过管道传输到某种进度条,例如在 zenity 中?

答案1

正如所写,它将被等待。对于脉动进度条:

#! /bin/sh -
export LC_ALL=C
cd /path/to/dir || exit
{
  md5=$(
    find . -type f -print0 |
      sort -z |
      xargs -r0 md5sum |
      md5sum
  )
  exec >&-
  zenity --info \
         --title="Checksum" \
         --text="$md5"
} | zenity --progress \
           --auto-close \
           --auto-kill \
           --pulsate \
           --title="${0##*/}" \
           --text="Computing checksum"

对于实际的进度条,您需要提前知道要处理的文件数量。

zsh

#! /bin/zsh -
export LC_ALL=C
autoload zargs
cd /path/to/dir || exit
{
  files=(.//**/*(ND.))
} > >(
  zenity --progress \
         --auto-close \
         --auto-kill \
         --pulsate \
         --title=$0:t \
         --text="Finding files"
)
md5=(
  $(
   zargs $files -- md5sum \
      > >(
        awk -v total=$#files '/\/\// {print ++n * 100 / total}' | {
          zenity --progress \
            --auto-close \
            --title=$0:t \
            --text="Computing checksum" || kill -s PIPE $$
        }) \
      | md5sum
  )
)
zenity --info \
       --title=$0:t \
       --text="MD5 sum: $md5[1]"

请注意,在C语言环境之外,至少在 GNU 系统上,文件名顺序是不确定的,因为某些字符排序相同,并且文件名不能保证由有效文本组成,因此如上所述LC_ALL=C

C 语言环境顺序也非常简单(基于字节值),并且在不同系统和版本之间都是一致的。

请注意,这意味着错误消息(如果有)将以英语显示,而不是用户的语言(但 、 等也Computing checksum没有Finding files本地化,所以也没关系)。

对您的方法的一些其他改进:

  • 使用-exec md5sum {} +or -print0 | xargs -r0 md5sum(或zargs等效项)可最大限度地减少调用次数md5sum,每次md5sum调用都会传递多个文件。意味着每个文件-exec md5sum {} \;运行一个,效率非常低。md5sum
  • 我们在传递到 之前对文件列表进行排序md5sum。一般来说,这样做sort -k2不起作用,因为文件名可以包含换行符。一般来说,基于行处理文件路径是错误的。您会注意到我们.//在 zsh 方法中使用前缀来能够awk可靠地计算文件。某些md5sum实现还提供-zNUL 分隔记录的选项。

答案2

该代码将等待findmd5sum命令完成。这只是正常行为,除非您需要&将命令发送到后台。

但是,您的 zenity 命令格式错误:在=.所以我猜测您看到的是一个空的禅定窗口,这就是您认为它没有等待的原因。再试一次,但删除空格:

#!/bin/bash

cd /path-to-directory
md5=$(find . -type f -exec md5sum {} \; | sort -k 2 | md5sum)

zenity --info \
--title="Calculated checksum" \
--text="$md5"

如果您这样做,您还可以避免需要cd并使其更加简洁:

#!/bin/bash

zenity --info \
--title="Calculated checksum" \
--text="$(find /path-to-directory -type f -exec md5sum {} \; | sort -k 2 | md5sum)"

如果您需要它始终返回相同的结果,无论目录的父路径是什么,您都可以使用它从命令的输出中删除文件名,find ... md5sum然后再传递给第二个md5sum

#!/bin/bash

zenity --info \
--title="Calculated checksum" \
--text="$(find /path-to-directory -type f -exec md5sum {} \; | cut -d ' ' -f1 | sort -k 2 | md5sum)"

相关内容