パイプの出力を複製できますか?

パイプの出力を複製できますか?

まあ、タスクは簡単です。スクリプトの一部で、md5 ハッシュと sha1 ハッシュの両方を計算する必要があります。入力はファイル (大きなファイル) で、ハッシュは、後で出力を作成するために MD 変数と SH 変数に格納する必要があります。

処理されたファイルは非常に大きい (数百 GB) ため、一度読み込んだデータを何らかの方法で複数回使用しようとします。プロセス置換と呼ばれるものを見つけたので、次の方法で採用しました。

$ dd if=big.tgz 2>/dev/null |tee >(sha1sum ) > >(md5sum ) ;

の代わりに:

$ SH=$(sha1sum big.tgz); MD=$(md5sum big.tgz);

しかし、次のものを見つけました:

  • どちらも約 40 秒かかるため、リソースも時間も節約できないようです (4.776 GB のファイルの場合)

  • >(md5sum )サブプロセスの結果を変数MDに保存して、後でスクリプトで使用する方法がわかりません。

私はパイプエクセックを理解しようとしましたが、素晴らしいカラーイラストでもまだ成功していません。

VAR=$(command) 以外に、出力を変数にリダイレクトする方法はありますか?

答え1

パフォーマンスに関しては、CPU によって制限される可能性があります。実際、MD5 と sha1sum の両方で 40 秒で 4.7 TB は高速に感じられます。したがって、この方法で作業する場合でも、ディスク IO が削減されることになります。

実際にこれを行う必要はありませんdd。sha1sumとmd5sumの出力をファイルに直接書き込んで後で使用することもできます。

tee < big.tgz  >(sha1sum > big.tgz.sha1 ) > >(md5sum > big.tgz.md5 )
sha1=`cat big.tgz.sha1`
md5=`cat big.tgz.md5`

私がこのような一時ファイル (big.tgz.sha1およびbig.tgz.md5) を使用することをお勧めします。私の知る限り、異なる値を持つ 2 つの変数を同時に設定する方法はないからです。1 つを直接変数にキャプチャすることはできますが、両方をキャプチャすることはできません。また、 と の両方md5sumsha1sum同時に同じ stdout に書き込むことを許可すると、予期しない問題が発生する可能性があります。

答え2

まあ、内部に別のリダイレクトを追加するだけです:

tee < big.tgz >(sha1sum > big.tgz.sha1sum) >(md5sum > big.tgz.md5sum)

sha1 と md5 を区別するのは簡単であることを考慮して、出力をそのまま取得することもできます (長さが異なるため、どちらがどちらか混乱することはありません)。

面倒な手続きを踏まずに、複数のチェックサムを独自に計算するユーティリティもありますtee

実際には、上記は なしでも記述できますtee

sha1sum big.tgz > big.tgz.sha1sum &
md5sum big.tgz > big.tgz.md5sum
wait # for sha1sum

理論的には、データがディスクから 2 回読み取られるため、これは良くありません。

実際には、両方のリーダーを並行して (およびバックグラウンドで) 実行すると、ディスク キャッシュがそれを処理できるようになり、データが実質的に 1 回だけ読み取られるようになります。これは、ハッシュ計算が高速で I/O が低速であるため、プロセスが他のプロセスから逃げることができないことを前提としています。

(以前、別の文脈で二度読むことについて投稿しました:md5sum で pv を使用する- 通常は機能しますが、多少のリスクが伴うため、teeより信頼性の高い方法です。

答え3

parsetGNU Parallel は変数を並列に設定するために作成されており、--tee入力を複数のコマンドに渡します。

parset md5,sha1,sha256 --pipe --tee {} ::: md5sum sha1sum sha256sum < bigfile
echo $sha1

parset sumarr --pipe --tee {} ::: md5sum sha1sum sha256sum < bigfile
echo ${sumarr[1]}

関連情報