根據 GNU Parallel 郵件列表,這不是 GNU Parallel 特有的問題。他們建議我在這裡發布我的問題。
我收到的錯誤是“管道損壞”錯誤,但我覺得我應該首先解釋問題的背景以及導致此錯誤的原因。當嘗試在 GNU Parallel 中使用任何包含「while read」迴圈的 bash 腳本時,就會發生這種情況。
我有一個像這樣的基本 bash 腳本:
#!/bin/bash
# linkcheck.sh
while read domain
do
host "$domain"
done
假設我想輸入一個大列表(例如 250mb)。
cat urllist | ./linkcheck.sh
在 250mb 的 URL 上執行主機指令相當緩慢。為了加快速度,我想在管道傳輸之前將輸入分解成區塊,然後並行運行多個作業。 GNU Parallel 能夠做到這一點。
cat urllist | parallel --pipe -j0 parallel ./linkcheck.sh {}
{} 逐行替換為 urllist 的內容。假設我的系統預設設定能夠為每個並行實例執行 500 個左右的作業。為了解決這個限制,我們可以並行化 Parallel 本身:
cat urllist | parallel -j10 --pipe parallel -j0 ./linkcheck.sh {}
這將運行 5000 個左右的工作。遺憾的是,它還會導致錯誤“管道損壞”(bash 常見問題)。然而,如果我刪除 while read 循環並直接從輸入到 {} 的內容中獲取輸入,腳本就會開始工作,例如,
#!/bin/bash
# linkchecker.sh
domain="$1"
host "$1"
為什麼它不能與 while read 迴圈一起使用?關閉 SIGPIPE 訊號來停止「損壞的管道」訊息是否安全,或會產生資料損壞等副作用?
謝謝閱讀。
答案1
所以,做了
貓網址列表 |並行 --pipe -j0 並行 ./linkcheck.sh {}
工作正常嗎?我相信你的部分問題可能是你遺漏了第二個--pipe
,如
貓網址列表 |並行-j10 --管道並行-j0- 管道./linkcheck.sh {}
順便說一句,你永遠不需要說
貓一個文件|一些命令
您可以隨時將其變更為
一些命令<一個文件
從而減少一個進程(以及一個管道)。 (cat
當您有多個輸入檔案時,使用它可能是適當/必要的。)
答案2
在我看來,錯誤可能是由於不良的競爭條件而引起的,因為在管道仍然打開時分叉子進程運行 linkcheck.sh 的另一個副本和子進程實際嘗試讀取之間存在視窗。在該視窗中,另一個副本已讀取 EOF 並且管道已關閉。