AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 495477
Accepted
EmmaV
EmmaV
Asked: 2019-01-20 08:29:33 +0800 CST2019-01-20 08:29:33 +0800 CST 2019-01-20 08:29:33 +0800 CST

将 pv 与 md5sum 一起使用

  • 772

我用来检查同一目录md5sum中pv的 4 GiB 文件:

md5sum dir/* | pv -s 4g | sort

该命令在大约 28 秒内成功完成,但pv输出全错。这是始终显示的那种输出:

219 B 0:00:07 [ 125 B/s ] [>                                ]  0% ETA 1668:01:09:02

没有-s 4gand也是这样| sort。我也尝试过使用不同的文件。

我试过使用pvwithcat并且输出很好,所以问题似乎是由md5sum.

pipe hashsum
  • 5 5 个回答
  • 1779 Views

5 个回答

  • Voted
  1. Best Answer
    Kusalananda
    2019-01-20T09:14:13+08:002019-01-20T09:14:13+08:00

    该pv实用程序是“花哨的cat”,这意味着您可以pv在大多数情况下使用cat.

    使用catwith md5sum,您可以计算单个文件的 MD5 校验和

    cat file | md5sum
    

    或者,与pv,

    pv file | md5sum
    

    不幸的是,这不允许md5sum将文件名正确插入到其输出中。

    现在,幸运的pv是,它真的很花哨cat,并且在某些系统(Linux)上,它能够观察正在通过另一个进程的数据。这是通过将其-d选项与该其他进程的进程 ID 一起使用来完成的。

    这意味着您可以执行以下操作

    md5sum dir/* | sort >sums &
    sleep 1
    pv -d "$(pgrep -n md5sum)"
    

    这将允许pv观看该md5sum过程。sleep允许md5sum在后台运行的 正确启动 。pgrep -n md5sum将返回您拥有的最近启动的md5sum进程的 PID。pv将在它正在监视的进程终止后立即退出。

    我已经测试了这种特殊的运行方式pv几次,它似乎通常运行良好,但有时它似乎停止输出任何东西作为md5sum切换到下一个文件。有时,它似乎会在 shell 中生成虚假的后台任务。

    运行它可能是最安全的

    md5sum dir/* >sums &
    sleep 1
    pv -W -d "$!"
    sort -o sums sums
    

    该-W选项将导致pv等待直到有实际数据正在传输,尽管这似乎并不总是可靠地工作。

    • 11
  2. ozzy
    2019-01-20T09:48:06+08:002019-01-20T09:48:06+08:00

    您通过管道提供的数据md5sum不是正在处理的文件的数据,而是md5sum输出,对于每个文件,输出由一行组成:MD5 哈希、两个空格和文件名。既然我们提前知道了这一点,就可以pv据此告知,从而使它能够显示一个准确的进度指示器。有两种方法可以这样做。

    第一种首选方法(由frostschutz 建议)利用了md5sum每个已处理文件生成一行的事实,以及pv具有计算行数而不是字节数的行模式这一事实。在这种模式下pv,只有在吞吐量中遇到换行符时才会移动进度条,即每个文件由md5sum. 在 Bash 中,第一种方法可能如下所示:

    set -- *.iso; md5sum "$@" | pv --line-mode -s $# | sort
    

    set内置函数用于为要处理的文件设置位置参数(外壳*.iso模式由外壳扩展)。md5sum然后被告知处理这些文件($@扩展为位置参数),并且pv在行模式下,每次处理文件/一行输出时都会移动进度指示器md5sum。值得注意的是,pv它可以预期的总行数 ( -s $#),因为特殊的 shell 参数$#扩展到位置参数的数量。

    第二种方法不是基于行,而是基于字节。有了md5sum这个不必要的复杂,但一些其他程序可能不会产生行,而是例如连续数据,然后这种方法可能更实用。我用它来说明它md5sum。这个想法是计算md5sum(或其他程序)将产生的数据量,并用它来通知pv. 在 Bash 中,这可能如下所示:

    os=$(( $( ls -1 | wc -c ) + $( ls -1 | wc -l ) * 34 ))
    md5sum * | pv -s $os | sort
    

    第一行计算输出大小 ( os) 估计值:第一项是编码文件名所需的字节数(包括换行符),第二项是用于编码 MD5 哈希的字节数(每个 32 个字节),加上2个空格。在第二行中,我们告诉我们pv预期的数据量是os字节,这样它就可以显示一个准确的进度指示器,直到 100%(每个完成的 md5summed 文件都会更新该指示器)。

    显然,这两种方法仅在要处理多个文件的情况下才实用。此外,应该注意的是,由于 的输出与程序必须花费在处理基础数据上md5sum的时间量无关,因此进度指标可能会被认为有些误导。md5sum例如,在第二种方法中,具有最短名称的文件将产生最低的进度更新,即使它实际上可能是最大的。再说一次,如果所有文件的大小和名称都相似,那应该没什么大不了的。

    • 5
  3. frostschutz
    2019-01-20T10:47:05+08:002019-01-20T10:47:05+08:00

    这是一个获取每个文件进度的肮脏技巧:

    for f in iso/*
    do
        pv "$f" | (
            cat > /dev/null &
            md5sum "$f"
            wait
        )
    done
    

    它看起来像什么:

    4.15GiB 0:00:32 [ 130MiB/s] [================================>] 100%            
    0db0b36fc7bad7b50835f68c369e854c  iso/KNOPPIX_V7.6.1DVD-2016-01-16-EN.iso
     792MiB 0:00:06 [ 130MiB/s] [================================>] 100%            
    97537db63e61d20a5cb71d29145b2937  iso/archlinux-2016.10.01-dual.iso
     843MiB 0:00:06 [ 129MiB/s] [================================>] 100%            
    1b5dc31e038499b8409f7d4d720e3eba  iso/lubuntu-16.04-desktop-i386.iso
     259MiB 0:00:02 [ 130MiB/s] [=========>                        ] 30% ETA 0:00:04
    ...
    

    现在,这做了几个假设。首先,读取数据比散列数据要慢。其次,该操作系统将缓存 I/O,因此即使数据不会被(物理)读取两次,pv并且md5sum是完全独立的读取器。

    这种肮脏、肮脏的 hack 的好处在于,您可以轻松地对其进行调整,以在所有数据上制作进度条,而不仅仅是一个文件。并且仍然会做一些奇怪的事情,比如事后对输出进行排序。

    pv iso/* | (
        cat > /dev/null &
        md5sum iso/* | sort
        wait
    )
    

    它看起来像什么(正在进行):

    15.0GiB 0:01:47 [ 131MiB/s] [===========================>      ] 83% ETA 0:00:21
    

    它的样子(完成):

    18.0GiB 0:02:11 [ 140MiB/s] [================================>] 100%            
    0db0b36fc7bad7b50835f68c369e854c  iso/KNOPPIX_V7.6.1DVD-2016-01-16-EN.iso
    155603390e65f2a8341328be3cb63875  iso/systemrescuecd-x86-4.2.0.iso
    1b5dc31e038499b8409f7d4d720e3eba  iso/lubuntu-16.04-desktop-i386.iso
    1b6ed6ff8d399f53adadfafb20fb0d71  iso/systemrescuecd-x86-4.4.1.iso
    25715326d7096c50f7ea126ac20eabfd  iso/openSUSE-13.2-KDE-Live-i686.iso
    ...
    

    现在,这是针对黑客的。检查其他答案以获得正确的解决方案。;-)

    • 2
  4. fra-san
    2019-01-20T10:23:07+08:002019-01-20T10:23:07+08:00

    正如评论和其他答案中已经指出的那样:

    1. 您pv只输入md5sum' 的输出:校验和和文件名;因此,pv的进度条无法显示md5sum正在读取的数据量。
    2. 4 GB 的大小当然是太多了。此外,提供pv您要输入的文件的大小(手动,使用-s)是不方便的。

    将文件内容输入pv然后输入md5sum会给您一个进度条,但文件名会丢失。

    这段代码不是那么优雅的方式,同时拥有一个有意义的进度条和带有校验和的文件名:

    #!/bin/sh
    
    for file in "$@"; do
        pv -- "$file" |
        md5sum |
        sed 's/-$//' |
        printf '%s%s\n' "$(cat -)" "$file"
    done
    

    该脚本的调用方式如下:

    ./script dir/*
    

    你当然可以将它声明为一个函数,以避免输入它的路径来调用它(或将它添加到你的PATH):

    function pvsum () {
        for file in "$@"; do
            pv -- "$file" |
              md5sum |
              sed 's/-$//' |
              printf '%s%s\n' "$(cat -)" "$file"
        done
    }
    

    这样,该命令pvsum dir/* | sort将等同于您的md5sum dir/* | pv -s <size> | sort.

    它的输出:

    $ ./testscript testdir/*
    4.00GiB 0:00:09 [ 446MiB/s] [==============================>] 100%            
    9dab5f8add1f699bca108f99e5fa5342  testdir/file1
    1.00GiB 0:00:02 [ 447MiB/s] [==============================>] 100%            
    06a738a71e3fd3119922bdac259fe29a  testdir/file2
    

    它能做什么:

    • 它遍历给定的文件,并且对于每个:
      • 将文件从管道传输pv到md5sum,显示默认进度条。
      • sed用于删除-打印的 by md5sum(从标准输入读取);这也试图使输出适合md5sum -c(感谢frostschutz指出这一点)1消耗。
      • 在标准输出上打印校验和,后跟文件名。

    关于sort:

    我不确定您的预期结果,所以我忽略了它。由于pv将其进度条写入标准错误,因此将所有内容通过管道传输sort将pv' 的输出与md5sum' 的输出分离。
    无论如何,您可以在上面的代码中追加 | sortafterdone并检查结果是否适合您。


    1md5sum -c请注意,如果文件名包含换行符,上面显示的代码的输出将不适合。处理换行符是可能的,但某些版本的md5sum行为在这方面有所不同(例如,请参阅此问题的答案),使得通用解决方案并不容易(并且超出了此答案的范围)。

    假设最新版本的md5sum,解决此问题的尝试可能是:

    for file in "$@"; do
        pv -- "$file" |
        md5sum |
        sed 's/-$//' |
        printf '%s%s\n' "$(cat -)" "$file" |
        sed -n 'H; 1h; $!d; g; s/\\/\\\\/g; s/\n/\\n/g; t x; p; q; :x s/^/\\/; p;'
    done
    

    唯一的加法,即 final sed,将:

    • 将当前文件的整个输入、校验和和名称放在模式空间中,因为它可能包含换行符:H将换行符和当前模式空间附加到保持空间;1h覆盖 previous H,仅针对第一行,执行相同但不附加换行符;$!d如果当前行不是最后一行,则开始一个新的循环;g将保持空间的内容放入模式空间。
    • 使用反斜杠 ( \) 转义生成的模式空间中的任何反斜杠。
    • 替换\n为结果模式空间中的任何换行符。
    • 仅当至少替换了反斜杠或换行符(t x: branch to label x)时,才会在校验和的开头添加反斜杠以md5sum -c表示必须对某些内容进行转义;否则就退出。p在这两种情况下,在退出之前将模式空间打印( )到标准输出(该选项-n禁用自动打印)。
    • 1
  5. sudodus
    2019-01-20T19:21:59+08:002019-01-20T19:21:59+08:00

    我也很喜欢驯服“花式猫” pv,因为md5sum:-)

    • 我认为我的 shellscript 现在相当稳定
    • usage如果您没有正确输入模式,则会出现输出。
    • 它适用于通配符,但不会递归到子目录
    • 您可以输入多个模式,例如".* *"
    • 有一个详细度开关可以打开检查 md5sums... OK
    • 您可以将相关输出重定向到文件中;的进程视图输出pv将保留在 {screen/terminal window}
    • 一个for循环有两个pv进程,一个全局的,每个文件一个,全局pv的‘只统计文件’,另一个测量传输的数据的速度和数量
    • ANSI 转义序列用于将过程视图保持在稳定位置

    我使用名称md5summer,使 shellscript 可执行并将其放在 PATH 中的目录中(我的~/bin目录,您可能更喜欢/usr/local/bin)。

    #!/bin/bash
    
    # date      sign     comment
    # 20190119  sudodus  created md5summer version 1.0
    
    if [ "$1" == "-v" ]
    then
     verbose=true
     shift
    else
     verbose=false
    fi
    if [ $# -ne 1 ]
    then
     echo "Usage:    $0  [-v]  <pattern>"
     echo "Example:  $0  '*.iso'      # notice the quotes"
     echo "          $0  -v  '*.iso'  # verbose"
     exit
    fi
    tmpstr=$(find $1 -maxdepth 0 -type f 2> /dev/null)
    if [ "$tmpstr" == "" ]
    then
     echo "No such file '$1'. Try another pattern!"
     exit
    fi
    
    tmpdir=$(mktemp -d)
    tmpfil="$tmpdir/fil1"
    tmpfi2="$tmpdir/fil2"
    resetvid="\0033[0m"
    prev2line="\0033[2F"
    next2line="\0033[2E"
    
    sln=1
    cln=0
    cnt=0
    for i in $1
    do
     if test -f "$i"
     then
      cln=$((cln+1))
      tmp=$(find -L "$i" -printf "%s")
      cnt=$((cnt+tmp))
     fi
    done
    echo "
                        number of files = $cln
                        total file size = $cnt B ~ $(($cnt/2**20)) MiB
    "
    for i in $1
    do
     if test -f "$i"
     then
      tmpnam=$(echo -n "$i")
      tmpsum=$(< "$i" pv -ptrbs "$cnt" | md5sum)
      sleep 0.05
      echo "$sln" | pv -ls "$cln" > /dev/null
      sleep 0.05
      sln="$sln
    $i"
      sleep 0.05
      printf "${tmpsum/\-}${tmpnam}\n" >> "$tmpfil"
      echo -ne "$prev2line" > /dev/stderr
     fi
    done
    
    sync
    sleep 0.1
    echo -ne "$next2line" > /dev/stderr
    
    echo "-----"
    if $verbose
    then
     sort -k2 "$tmpfil" | tee "$tmpfi2" | md5sum -c
     echo "-----"
     cat "$tmpfi2"
    else
     sort -k2 "$tmpfil"
    fi
    sleep 0.5
    sync
    rm -r "$tmpdir"
    

    演示示例

    用法

    $ md5summer 
    Usage:    /home/sudodus/bin/md5summer  [-v]  <pattern>
    Example:  /home/sudodus/bin/md5summer  '*.iso'      # notice the quotes
              /home/sudodus/bin/md5summer  -v  '*.iso'  # verbose
    

    我在这个目录下测试过

    $ ls -1a
    .
    ..
    'filename with spaces'
    md5summer
    md5summer1
    md5summer2
    subdir
    .ttt
    zenity-info-message.png
    

    正常使用加模式查看隐藏文件

    $ md5summer ".* *"
    
                        number of files = 6
                        total file size = 12649 B ~ 0 MiB
    
    8,32KiB 0:00:00 [ 156MiB/s] [=============================>                ] 67%
    6,00  0:00:00 [ 133k/s] [====================================>] 100%            
    -----
    184d0995cc8b6d8070f89f15caee35ce  filename with spaces
    28227139997996c7838f07cd4c630ffc  md5summer
    3383b86a0753e486215280f0baf94399  md5summer1
    28227139997996c7838f07cd4c630ffc  md5summer2
    31cd03f64a466e680e9c22fef4bcf14b  .ttt
    670b8db45e57723b5f1b8a63399cdfa1  zenity-info-message.png
    

    详细输出加上模式以查看隐藏文件

    $ md5summer -v ".* *"
    
                        number of files = 6
                        total file size = 12649 B ~ 0 MiB
    
    8,32KiB 0:00:00 [ 184MiB/s] [=============================>                ] 67%
    6,00  0:00:00 [ 133k/s] [====================================>] 100%            
    -----
    filename with spaces: OK
    md5summer: OK
    md5summer1: OK
    md5summer2: OK
    .ttt: OK
    zenity-info-message.png: OK
    -----
    184d0995cc8b6d8070f89f15caee35ce  filename with spaces
    28227139997996c7838f07cd4c630ffc  md5summer
    3383b86a0753e486215280f0baf94399  md5summer1
    28227139997996c7838f07cd4c630ffc  md5summer2
    31cd03f64a466e680e9c22fef4bcf14b  .ttt
    670b8db45e57723b5f1b8a63399cdfa1  zenity-info-message.png
    

    重定向到一个文件,首先是屏幕输出

    $ md5summer ".* *" > subdir/save
    8,32KiB 0:00:00 [ 180MiB/s] [=============================>                ] 67%
    6,00  0:00:00 [ 162k/s] [====================================>] 100%            
    

    然后保存的输出

    $ cat subdir/save 
    
                        number of files = 6
                        total file size = 12649 B ~ 0 MiB
    
    -----
    184d0995cc8b6d8070f89f15caee35ce  filename with spaces
    28227139997996c7838f07cd4c630ffc  md5summer
    3383b86a0753e486215280f0baf94399  md5summer1
    28227139997996c7838f07cd4c630ffc  md5summer2
    31cd03f64a466e680e9c22fef4bcf14b  .ttt
    670b8db45e57723b5f1b8a63399cdfa1  zenity-info-message.png
    

    检查iso文件

    $ md5summer "*.iso"
    
                        number of files = 10
                        total file size = 7112491008 B ~ 6783 MiB
    
    28,0MiB 0:00:00 [ 160MiB/s] [>                                             ]  0%
    10,0  0:00:00 [ 204k/s] [====================================>] 100%            
    -----
    7a27fdd46a63ba4375896891826c1c88  debian-live-8.6.0-amd64-lxde-desktop.iso
    d70eec28cdbdee7f7aa95fb53b9bfdac  debian-live-8.7.1-amd64-standard.iso
    382cfbe621ca446d12871b8945b50d20  debian-live-8.8.0-amd64-standard.iso
    44473dfe2ee1aad0f71506f1d5862457  debian-live-8.8.0-i386-standard.iso
    f396b3532fa84059e7738c3c1827bada  debian-live-9.3.0-amd64-cinnamon.iso
    8f6def28ae7cbefa0a6e59407c884466  debian-live-9.6.0-amd64-cinnamon.iso
    90b1815da0a5bf4ee4b00eec2b5d3587  debian-testing-amd64-netinst_2017-07-28.iso
    8f75074ab98e166b7469299d3e459ac6  mini-amd64-2016-01-21-daily.iso
    e580266fba58eb34b05bf6e13f51a047  mini-jessie-32.iso
    646c109a9a16c0527ce1c7afa922e2ed  mini-jessie-64.iso
    
    • 1

相关问题

  • 如何在 bash 中使用“sudo”调用时将“yes”或“y”通过管道传输到程序中?

  • 将句柄传递给标准输入下行管道

  • 如何通过管道传输 bash 命令并保持 Ctrl+C 正常工作?

  • 为什么管道`mysql`到'tail'会改变输出格式?

  • `tee` 和 `bash` 进程替换顺序

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve