web-dev-qa-db-ja.com

md5sumでのpvの使用

同じディレクトリにあるファイルの4 GiBを確認するためにpvとともにmd5sumを使用しました:

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

コマンドは約28秒で正常に完了しますが、pvの出力はすべて間違っています。これは全体に表示される種類の出力です。

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

-s 4g| sortがなくても、このようになります。別のファイルでも試してみました。

pvcatとともに使用してみましたが、出力は問題なかったため、問題はmd5sumが原因であるようです。

6
EmmaV

pvユーティリティは「ファンシーcat」です。つまり、pvを使用するほとんどの状況でcatを使用できます。

catmd5sumとともに使用すると、単一ファイルのMD5チェックサムを次のように計算できます

cat file | md5sum

または、pvを使用して、

pv file | md5sum

残念ながら、これではmd5sumが出力にファイル名を適切に挿入することができません。

幸いなことに、pvreallyファンシーcatであり、一部のシステム(Linux)ではwatch別のプロセスを通過した。これは、その-dオプションを他のプロセスのプロセスIDとともに使用することによって行われます。

つまり、次のようなことができます

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

これにより、pvmd5sumプロセスを監視できるようになります。 sleepは、バックグラウンドで実行されているmd5sumが適切に起動できるようにするためにあります。 pgrep -n md5sumは、所有している最後に開始されたmd5sumプロセスのPIDを返します。 pvは、監視しているプロセスが終了するとすぐに終了します。

私はpvを実行するこの特定の方法を数回テストしましたが、それは一般的にはうまく機能しているようですが、md5sumが次のファイルに切り替えると、何も出力されなくなる場合があります。時々、それはシェルで偽のバックグラウンドタスクを生み出すようです。

おそらくそれを次のように実行するのが最も安全でしょう

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

-Wオプションは、実際のデータが転送されるまでpvを待機させますが、これも常に確実に機能するとは限りません。

11
Kusalananda

パイプを介して供給しているデータは、md5sumが処理しているファイルのデータではなく、md5sum出力であり、すべてのファイルについて、MD5-ハッシュ、2つのスペース、およびファイル名。これは事前にわかっているので、それに応じてpvに通知し、正確な進行状況インジケーターを表示できるようにすることができます。これには2つの方法があります。

最初の推奨される方法(frostschutzが推奨)は、md5sumが処理済みファイルごとに1行を生成することと、pvがバイトではなく行をカウントする行モードを使用することを利用しています。このモードでは、pvは、スループットで改行が検出されたとき、つまりmd5sumで終了したファイルごとにのみ、進行状況バーを移動します。 Bashでは、この最初のメソッドは次のようになります。

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

setビルトインは、位置パラメータを処理するファイルに設定するために使用されます(*.isoシェルパターンはシェルによって展開されます)。次に、md5sumはこれらのファイルを処理するように指示され($@は定位置パラメーターに展開されます)、行モードのpvは、ファイルが処理されるたびに、進行状況インジケーターを移動します/行md5sumによって出力されます。特に、特別なシェルパラメータ-s $#は位置引数の数に拡張されるため、pvには、予想される行の総数($#)が通知されます。

2番目の方法は、行ベースではなくバイトベースです。 md5sumを使用すると、これは不必要に複雑になりますが、他のプログラムでは行を生成せずに、たとえば連続データを生成する場合があるため、このアプローチの方がより実用的です。私はmd5sumで説明しています。アイデアは、md5sum(または他のプログラム)が生成するデータの量を計算し、これを使用してpvに通知することです。 Bashでは、これは次のようになります。

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

最初の行は出力サイズ(os)の見積もりを計算します。最初の項はファイル名のエンコードに必要なバイト数(改行を含む)、2番目の項はMD5ハッシュのエンコードに使用されるバイト数です(各32バイト)、および2つのスペース。 2行目では、予想されるデータ量がpvバイトであることをosに伝え、100%までの正確な進行状況インジケーターを表示できるようにします(このインジケーターは、終了したmd5summedごとに更新されますファイル)。

明らかに、どちらの方法も、複数のファイルを処理する場合にのみ実用的です。また、md5sumの出力はmd5sumプログラムが基礎となるデータの処理に費やす必要のある時間とは関係がないため、進行状況インジケータは誤解を招く可能性があると見なされる場合があることに注意してください。たとえば、2番目の方法では、実際にサイズが最も大きくても、最も短い名前のファイルの進行状況の更新が最も少なくなります。繰り返しになりますが、すべてのファイルのサイズと名前が同じであれば、これはそれほど重要ではありません。

5
ozzy

ファイルごとに進行状況を取得するための汚いハックは次のとおりです。

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
...

今、これはいくつかの仮定をします。まず、そのデータの読み取りはハッシュよりも遅いです。次に、そのOSはI/Oをキャッシュするため、pvmd5sumは完全に独立したリーダーであるにもかかわらず、データが(物理的に)2回読み取られることはありません。

このようなダーティでダーティなハックのいいところは、1つのファイルだけでなく、すべてのデータにわたってプログレスバーを作成するように簡単に調整できることです。そして、出力を後でソートするなど、変なことをします。

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
frostschutz

コメントやその他の回答ですでに指摘したように:

  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/* | sortmd5sum 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は、-によって出力されたmd5sum(標準入力から読み取っている)を削除するために使用されます。これはまた、出力をmd5sum -cで使用するのに適したものにしようとします(これを指摘してくれた frostschutz に感謝します)1
    • チェックサムとそれに続くファイル名を標準出力に出力します。

sortについて:

期待される結果がわからないので無視しました。 pvは進行状況バーを標準エラーに書き込むため、すべてをsortにパイプすると、pvの出力がmd5sumの出力から切り離されます。
とにかく、上記のコードのdoneの後に| sortを追加するだけで、結果に問題がないかどうかを確認できます。


1 上記のコードからの出力は、ファイル名に改行が含まれている場合、md5sum -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

唯一の追加、最後のsedは次のようになります。

  • 改行を含む可能性があるため、現在のファイルの入力全体、チェックサム、および名前をパターンスペースに入れます。Hは、改行と現在のパターンスペースをホールドスペースに追加します。 1hは、最初の行についてのみ以前のHをオーバーライドし、同じことを行いますが、改行を追加しません。 $!dは、現在の行が最後の行でない場合、新しいサイクルを開始します。 gは、ホールドスペースのコンテンツをパターンスペースに配置します。
  • 結果のパターンスペースにバックスラッシュ(\)を付けてエスケープします。
  • 結果のパターンスペースの改行を\nで置き換えます。
  • 少なくともバックスラッシュまたは改行が置き換えられた場合のみ(t x:ラベルxへの分岐)、チェックサムの先頭にバックスラッシュが追加され、md5sum -cに何かを通知するエスケープしないでください。それ以外の場合は単に終了します。どちらの場合も、終了する直前にパターンスペースを標準出力に印刷(p)します(オプション-nは自動印刷を無効にします)。
1
fra-san

私はまた、md5sumのために「ファンシーキャット」pvを飼いならすことを楽しんでいます:-)

  • 私のシェルスクリプトは今やや安定していると思います
  • パターンを正しく入力しないと、usage出力が表示されます。
  • ワイルドカードで動作しますが、サブディレクトリに再帰しません
  • 複数のパターンを入力できます(例:".* *"
  • Md5sumsのチェックをオンにする冗長スイッチがあります... OK
  • 関連する出力をファイルにリダイレクトできます。 pvのプロセスビュー出力は{画面/ターミナルウィンドウ}に残ります
  • Forループには2つのpvプロセスがあり、1つはグローバルファイル、各ファイルは1つ、グローバルpvは「ファイルのみをカウント」し、もう1つは転送されるデータの速度と量を測定します
  • ANSIエスケープシーケンスは、プロセスビューを安定した位置に保つために使用されます。

私はmd5summerという名前を使用し、シェルスクリプトを実行可能にして、それを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
sudodus