簡體   English   中英

如何在bash讀取語句中檢測失敗的子進程?

[英]How do I detect a failed subprocess in a bash read statement?

在bash中,我們可以使用read和pipe到一個子進程從一系列命令設置一個環境變量。 但是我在一個邊緣情況下檢測我的處理中的錯誤時遇到了問題 - 在錯誤發生之前,子流程管道的一部分會產生一些輸出。

一個采用輸入文件的簡化示例,查找以“foo”開頭的行,並將var設置為該行的第一個單詞:

set -e
set -o pipefail
set -o nounset

die() {
  echo $1 > /dev/stderr
  exit 1
}

read -r var rest < <( \
    cat data.txt \
    | grep foo \
    || die "PIPELINE" \
) || die "OUTER"

echo "var=$var"

data.txt一樣運行它

blah
zap foo awesome
bang foo

將輸出

var=zap

在不包含foo輸出的data.txt文件上運行它(到stderr)

DEAD: PIPELINE
DEAD: OUTER

這一切都符合預期。

我們可以在流程結束時引入另一個cat無操作階段

...
read -r var rest < <( \
    cat data.txt \
    | grep foo \
    | cat \
    || die "PIPELINE" \
) || die "OUTER"
...

一切都繼續有效。

但是如果附加階段是paste -s -d' '並且輸入不包含“foo”,則輸出為

var=
DEAD: PIPELINE

這似乎表明管道錯誤,但讀取成功與空行。 (看起來像paste -s -d' '輸出一行輸出,即使它的輸入是空的。)

有沒有一種簡單的方法來檢測管道的這種故障,並導致主腳本出錯?

我想我可以檢查變量是不是空的 - 但這是一個簡化版本 - 我實際上是使用sedpaste來連接多行來設置多個變量,比如

read -r v1 v2 v3 rest < <( \
   cat data.txt \
   | grep "^foo=" \
   | sed -e 's/foo=//' \
   | paste -s -d' ' \
   || die "PIPELINE"
) || die "OUTER"

您可以使用另一個grep來查看paste的輸出是否包含以下內容:

read -r var rest < <( \
    cat data.txt \
    | grep foo \
    | paste -s -d' '  \
    | grep . \
    || die "PIPELINE" \
) || die "OUTER"

最后,我根據具體情況選擇了兩種不同的解決方案。

第一種是將結果傳遞給臨時文件。 這將在執行讀取之前處理整個文件,因此管道中的任何故障都將導致腳本失敗。

cat data.txt \
    | grep "^foo=" \
    | sed -e 's/foo=//' \
    | paste -s -d' ' \
    > $TMP/result.txt
    || die "PIPELINE"

read -r var rest < $TMP/result.txt || die "OUTER"

第二個是測試變量是否已設置。 雖然這意味着我想避免一堆重復,但它似乎是最防彈的解決方案。

read -r var rest < <( cat data.txt \
    | grep "^foo=" \
    | sed -e 's/foo=//' \
    | paste -s -d' ' \
    || die "PIPELINE"
    ) || die "OUTER"

 [ ! -z "$var" ] || die "VARIABLE NOT SET"

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM