使用 GNU Parallel 執行時,Bash 腳本「while read」循環會導致「管道損壞」錯誤

使用 GNU Parallel 執行時,Bash 腳本「while read」循環會導致「管道損壞」錯誤

根據 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 並且管道已關閉。

相關內容