2012-03-09 108 views
5

更新:雖然沒有真正解決帶有問候我管的努力原來的問題,我已經解決了我的問題通過大大簡化它,並且完全拋棄管道。這是一個概念證明腳本,它可以並行生成一次,同時從磁盤讀取一次CRC32,MD5,SHA1,SHA224,SHA256,SHA384和SHA512校驗和,並將它們作爲JSON對象返回(將使用PHP中的輸出和Ruby)。這是沒有錯誤檢查粗糙,但它的工作原理:可能的競爭條件

#!/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。最初,我只是一個簡單的腳本,寫了一個簡單的腳本,用三個cfv命令寫了三個cfv命令,然後寫入/ tmp /下的三個單獨的文件,然後嘗試將它們提供給標準輸出,但最終除非我在嘗試讀取文件之前讓腳本睡了一秒,否則會產生空輸出。這種想法很奇怪,我認爲我在我的腳本中是一個白癡,所以我試圖通過讓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 

但是,隨着註釋掉睡眠1秒我一開始預期的輸出,

[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接收者,它派生的數據已經退出,因此回聲「EOP」聲明將前直到所有的cfv子流完成,這意味着他們已經將他們的輸出寫到我命名的管道中了......然後echo語句會執行。

由於行爲是沒有管相同,只是用輸出的臨時文件,我想這一定是具有三通將數據推到它的接受者的方式做一些競爭條件?我嘗試了一個簡單的「等待」命令,但它當然會等待我的bash子進程 - 即while循環 - 完成,所以我只是得到一個掛起的進程。

任何想法?

TIA, 丹尼爾:)一旦寫輸入的最後一位到最後輸出管道,並將其關閉(

+1

我期望有這些校驗和的源代碼可用。如何將它們組合成1個程序,並將3個值寫入相應的校驗和文件。我不得不相信,perl可能有這個模塊,你可以一起做一個文件傳遞。 (只是想着這個盒子,YRMV)。祝你好運! – shellter 2012-03-10 01:25:51

+1

這會有幫助嗎? 'parallel --group'cfv -C -t sfv -f {} - ; cfv -C -t sha1 -f {} - ; cfv -C -t md5 -f {} - ;' ::: file' – potong 2012-03-10 01:46:36

+0

@shelter - 我想寫我自己的例程總是我的後備,但我更願意使用盡可能多的工具。 – DanielSmedegaardBuus 2012-03-10 08:32:26

回答

2

發球將退出即通過慶典創建的命名管道,而不是你的FIFO,又名「命名管道「)。它不需要等待讀取管道的過程完成;事實上,它不知道它甚至寫入管道。由於管道有緩衝區,很可能在TED完成寫入之前,另一端的進程完成讀取。所以腳本會將'EOP'寫入fifo,導致讀取循環終止。這將關閉fifo的唯一讀者,並且所有cfv進程在下次嘗試寫入stdout時都將獲得SIGPIPE。

這裏要問的一個顯而易見的問題是爲什麼你不只是運行三個(或N個)獨立的進程來讀取文件和計算不同的摘要。如果「文件」實際上是在飛行中生成的或從某個遠程站點下載的,或者是某個其他緩慢的過程,那麼按照您嘗試執行操作的方式執行操作可能是有意義的,但如果該文件存在於本地磁盤,很可能只有一個磁盤訪問實際發生;滯後的彙總器將從緩衝區緩存中讀取文件。如果這就是你所需要的,那麼GNU並行應該可以正常工作,或者你可以用bash(&)啓動進程,然後等待它們。 YMMV,但我認爲這些解決方案中的任何一個都比建立所有這些管道並用tee模擬用戶區中的緩衝區緩存資源要少。

順便說一句,如果你想序列化來自多個進程的輸出,你可以使用flock工具。僅僅使用fifo是不夠的;不能保證寫入fifo的流程會以原子方式編寫整行代碼,如果您知道他們這樣做了,則不需要fifo。