如果前一個命令失敗則退出管道

如果前一個命令失敗則退出管道

我試圖透過解析腳本的輸出來檢查正在運行和排隊的 PBS 作業的qstat -tn1數量bash。到目前為止,這已經奏效了:

count ()
{
    qstat -tn1 | awk '
        BEGIN { R = 0; Q = 0; }
        $10 == "R" { R++ }
        $10 == "Q" { Q++ }
        END { print R, Q }'
}

if read -r R Q < <(count)
    ...

然而,我發現qstat有時會因未知原因而失敗。在這種情況下,它不會向 列印任何內容stdout,並向 列印一些錯誤訊息stderr,並以非零狀態退出(相當標準)。然而,awk不知道qstat失敗了,並高興地列印0 0收到的空輸入。然後read將 0 分配給兩者R,並且Q不知道qstat實際上失敗了。

  1. 我需要在腳本區塊中使用 0R進行初始化,因為可能沒有正在運行的進程或沒有排隊的進程,並且我需要列印,而不僅僅是一個空字串來獲取此類進程的數量。QBEGINawk0
  2. 我可以這樣做set -o pipefail,這將允許count以非零狀態退出,但read看不到退出狀態,並且無論如何awk都會執行並列印0 0空輸入。
  3. 我可以嘗試命名管道和子進程,但必須管理它們感覺太複雜了。

有什麼好的方法可以讓呼叫者count偵測到它的失敗嗎?

答案1

我認為讀取count進程替換會阻止您獲取其返回狀態。所以不要這樣做。相反,請將結果儲存在變數中,或使用管道。

count=$(count)
if [ $? -eq 0 ]; then
  read -r R Q <<<"$count"

或者

set -o pipefail
if count | { read -r R Q; … }

另一種可能性是使用PIPESTATUS變數來檢查第一個命令的回傳狀態。

count=$(qstat -tn1 | awk …)
if ((${PIPESTATUS[0]} == 0)); then
  read P Q

或者,安排 awk 在其輸入為空時列印一些獨特的內容(例如,什麼也沒有)。

awk '
    BEGIN { R = 0; Q = 0; }
    $10 == "R" { R++ }
    $10 == "Q" { Q++ }
    END { if (NR) print R, Q }'

ifne您可以使用from測試命令的輸入是否為空更多實用程式或者其他方法。但既然您要透過管道連接到 awk,那麼您不妨在現有的 awk 腳本中執行此操作。

如果需要從qstat命令取得返回狀態,可以將其作為額外的輸入行提供給 awk。為了更容易解析,請安排最後一行具有唯一的格式。

{
  qstat -tn1
  echo exit_code = $?
} | awk '
    /^exit_code = / { status = $3 }
    END { if (status == 0) print Q, R }
'

答案2

這:

count ()
{
    { qstat -tn1 || echo "EPIC FAIL" } | awk '
        BEGIN { R = 0; Q = 0; }
        $10 == "R" { R++ }
        $10 == "Q" { Q++ }
        END { print R, Q }'
}

if read -r R Q < <(count)
    ...

如果qstat成功,其輸出將發送到awk。如果qstat傳回非零狀態,則文字「EPIC FAIL」將會傳送至awk

這只是一個例子。將 echo 替換為您可以在內部awk或使用處理的適當內容if read

相關內容