2012-03-09 5 views
5

UPDATE:私の配管工事に関して提示された元の問題を実際に解決していない間に、それを大幅に簡素化し、パイプを完全に排除するだけです。ここでは、ディスクから一度だけ読み取ってCRC32、MD5、SHA1、SHA224、SHA256、SHA384、SHA512のチェックサムを生成し、それらをJSONオブジェクトとして返すコンセプト実証スクリプトを作成します(PHPで出力を使用します)。 Rubyなど)。それをエラーチェックせずに、粗製だが、それは動作します:BASHスクリプト内の名前付きパイプに順序外れして到着した複数のティー受信者からのパイプ出力による競合状態

#!/bin/bash 

checksums="`tee <"$1" \ 
     >(cfv -C -q -t sfv -f - - | tail -n 1 | sed -e 's/^.* \([a-fA-F0-9]\{8\}\)$/"crc32":"\1"/') \ 
     >(md5sum - | sed -e 's/^\([a-fA-F0-9]\{32\}\) .*$/"md5":"\1"/') \ 
     >(sha1sum - | sed -e 's/^\([a-fA-F0-9]\{40\}\) .*$/"sha1":"\1"/') \ 
     >(sha224sum - | sed -e 's/^\([a-fA-F0-9]\{56\}\) .*$/"sha224":"\1"/') \ 
     >(sha256sum - | sed -e 's/^\([a-fA-F0-9]\{64\}\) .*$/"sha256":"\1"/') \ 
     >(sha384sum - | sed -e 's/^\([a-fA-F0-9]\{96\}\) .*$/"sha384":"\1"/') \ 
     >(sha512sum - | sed -e 's/^\([a-fA-F0-9]\{128\}\) .*$/"sha512":"\1"/') \ 
     >/dev/null`\ 
" 

json="{" 

for checksum in $checksums; do json="$json$checksum,"; done 

echo "${json:0: -1}}" 

元の質問:

私はその適用後に私の検索フレーズには多くのヒットを得たように私は、この質問をして少し怖いですUsing named pipes with bash - Problem with data lossから収穫された知識と別の20ページを読むと、私はまだこれで少し静止しています。

それでも、ディスク上から一度だけ読み取っている間に、CRC32、MD5、およびSHA1チェックサムを同時にファイルに作成できるようにする簡単なスクリプトを実行しています。私はその目的のためにcfvを使用しています。

元々、/ tmp /の下にある3つの別々のファイルに3つのcfvコマンドを書き込んでファイルをcat'tedしてから、stdoutにキャッチしようとしましたが、ファイルを読み込もうとする前にスクリプトを1秒間スリープさせない限り、空の出力があります。変わったと思ったので、私は自分のスクリプトでは馬鹿だと思ったので、代わりにcfvワーカーを名前付きパイプに出力させることで別のアプローチを試みました。これまでのところ、これはforementionedリンクから技術を適用した後、私のスクリプトです:

ので
!/bin/bash 

# Bail out if argument isn't a file: 
[ ! -f "$1" ] && echo "'$1' is not a file!" && exit 1 

# Choose a name for a pipe to stuff with CFV output: 
pipe="/tmp/pipe.chksms" 

# Don't leave an orphaned pipe on exiting or being terminated: 
trap "rm -f $pipe; exit" EXIT TERM 

# Create the pipe (except if it already exists (e.g. SIGKILL'ed b4)): 
[ -p "$pipe" ] || mkfifo $pipe 

# Start a background process that reads from the pipe and echoes what it 
# receives to stdout (notice the pipe is attached last, at done): 
while true; do 
     while read line; do 
       [ "$line" = "EOP" ] && echo "quitting now" && exit 0 
       echo "$line" 
     done 
done <$pipe 3>$pipe & # This 3> business is to make sure there's always 
         # at least one producer attached to the pipe (the 
         # consumer loop itself) until we're done. 

# This sort of works without "hacks", but tail errors out when the pipe is 
# killed, naturally, and script seems to "hang" until I press enter after, 
# which I believe is actually EOF to tail, so it's no solution anyway: 
#tail -f $pipe & 

tee <"$1" >(cfv -C -t sfv -f - - >$pipe) >(cfv -C -t sha1 -f - - >$pipe) >(cfv -C -t md5 -f - - >$pipe) >/dev/null 

#sleep 1s 
echo "EOP" >$pipe 
exit 

、それはスタンドとして実行、私はこの出力を得る:

[email protected]:~/tisso$ ./multisfv file 
: : : quitting now 
- : Broken pipe (CF) 
close failed in file object destructor: 
sys.excepthook is missing 
lost sys.stderr 
- : Broken pipe (CF) 
close failed in file object destructor: 
sys.excepthook is missing 
lost sys.stderr 
- : Broken pipe (CF) 
[email protected]:~/tisso$ close failed in file object destructor: 
sys.excepthook is missing 
lost sys.stderr 

しかし、睡眠1Sをコメントアウト私は考えていないの出口各CFV受信者の後までそれフォークデータが終了したために、ひいてはエコー「EOP」声明そのTシャツを前提としたいように、私が予想を取得出力、

[email protected]:~/tisso$ ./multisfv file 
3bc1b5ff125e03fb35491e7d67014a3e * 
-: 1 files, 1 OK. 0.013 seconds, 79311.7K/s 
5e3bb0e3ec410a8d8e14fef1a6daababfc48c7ce * 
-: 1 files, 1 OK. 0.016 seconds, 62455.0K/s 
; Generated by cfv v1.18.3 on 2012-03-09 at 23:45.23 
; 
2a0feb38 
-: 1 files, 1 OK. 0.051 seconds, 20012.9K/s 
quitting now 

これは、私をパズルだろう元すべてのcfvサブストリームが終了するまで実行してください。そうすれば、私の名前付きパイプに出力を書き込んだのでしょう...そして、echo文が実行されます。

出力テンポラリファイルを使用するだけで、パイプなしで動作が同じであるため、ティーがデータを受信者にプッシュする方法と関係があります。私は単純な "wait"コマンドを試しましたが、もちろんbashの子プロセス(whileループ)が終了するのを待つので、ちょうどぶら下がったプロセスになります。

アイデア?

TIA、 ダニエル:)

+1

これらのチェックサムに使用できるソースコードがあると思います。どのようにそれらを1つのプログラムに結合し、適切なチェックサムファイルに処理する3つの値を書き出すのですか?私はperlがおそらくこのモジュールを持っていると信じなければなりません。もう一度、あなたは一緒にglomをしてファイルを1回だけ渡すことができます。 (ちょうどこれの上にボックスを考える、YRMV)。がんばろう! – shellter

+1

これは役に立ちますか? cfv -C -t sdv -f {} - ; cfv -C -t sha1 -f {} - ; cfv -C -t md5 -f {} - ; 'パラレル - :::ファイル ' – potong

+0

@shelter - 私自身のルーチンを書くことは常に私の後戻りだと思うが、私は可能な限り多くのツールを利用したい。 – DanielSmedegaardBuus

答えて

2

それが最後の出力パイプに入力の最後のビットを書き込み、それを閉じた後ティー」は別名、それは、bashのではなく、あなたのFIFOにより作成された名前なしパイプである(終了します名前付きパイプ ")。パイプを読み取るプロセスが終了するのを待つ必要はありません。確かに、それはパイプに書き込んでいることも知らない。パイプにはバッファがあるので、もう一方のプロセスが読み終わる前にteeが書き込みを終了する可能性が非常に高いです。したがって、スクリプトはFIFOに 'EOP'を書き込んで、読み込みループを終了させます。それはfifoの唯一の読者を閉じ、次のstdoutへの書き込みを試みるときにすべてのcfvプロセスがSIGPIPEを取得します。

ここでは、3つ(またはN)の独立したプロセスを実行してファイルを読み込んで、異なるサマリーを計算するだけではないかという疑問があります。 「ファイル」が実際にオンザフライで生成されたり、リモートサイトやその他の遅いプロセスからダウンロードされた場合、ファイルを実行しようとしていることを行うのが理にかなっていますが、ファイルがローカルにある場合実際にディスクアクセスが1つしか起こらない可能性は非常に高いです。遅れたサマライザはバッファキャッシュからファイルを読み込みます。 GNU並列はうまく動作するはずです。あるいは、プロセスをbash(&)で起動し、それらを待つだけで済みます。 YMMVだが、これらのソリューションのいずれも、これらのパイプをすべて設定して、ユーザー・エリアのバッファ・キャッシュをティーでシミュレートするよりも、リソースの消費量が少なくなると思うだろう。

ところで、複数のプロセスから出力をシリアル化する場合は、flockユーティリティを使用できます。 FIFOを使うだけでは不十分です。 FIFOに書き込むプロセスがすべての行を原子的に書き込むという保証はなく、もしそれを知っていれば、FIFOは必要ありません。

関連する問題