Bash

我們可以在 tee(或 pee)命令中使用 $PIPESTATUS 嗎?

  • October 8, 2021

在我的 bash 腳本中,我經常使用管道,並且想知道管道的哪個階段導致出現錯誤時出現問題。這些片段的基本結構是:

#!/bin/bash

ProduceCommand 2>/dev/null | ConsumeCommand >/dev/null 2>&1
PipeErrors=("${PIPESTATUS[@]}")
[[ "${PipeErrors[0]}" -eq '0' ]] || { HandleErrorInProduceCommand; }
[[ "${PipeErrors[1]}" -eq '0' ]] || { HandleErrorInConsumeCommand; }

tee現在(第一次很有趣)我處於這樣一種情況,如果我可以使用or ,那就太好了pee。但是$PIPESTATUS在使用這些命令時會發生什麼?例如:

#!/bin/bash

ProduceCommand 2>/dev/null | tee >(ConsumeCommand1) >(ConsumeCommand2) >/dev/null 2>&1
PipeErrors=("${PIPESTATUS[@]}")

或者

#!/bin/bash

ProduceCommand 2>/dev/null | pee ConsumeCommand1 ConsumeCommand2 2>/dev/null
PipeErrors=("${PIPESTATUS[@]}")

我相信在這兩種情況下都${PipeErrors[0]}反映了ProduceCommand. 此外,假設它分別${PipeErrors[1]}反映了teepee本身的錯誤狀態是合乎邏輯的。

但這導致我至少遇到兩個理解問題:

  1. teeor的錯誤狀態(返回值)是pee什麼?我在手冊頁中沒有找到關於這一點的準確陳述。如果其中一個消費命令失敗,它們是否會返回硬編碼的錯誤狀態,或者它們是否會以某種方式傳遞消費命令的錯誤狀態(ssh例如)?如果是前者,我們如何找出哪些消耗命令是罪魁禍首?如果是後者,中繼哪個錯誤狀態?僅僅是首先失敗的命令嗎?
  2. AFAIK、bash 或teeorpee命令本身分別在內部使用管道(fifos)來獲取ProduceCommand消耗命令的輸出。這意味著我們有一個管道,其(第一個,在這種情況下,唯一的)接收端是一個管道本身。這不應該影響$PipeErrors上面的範常式式碼,但我真的不確定。

有人可以對此有所了解嗎?

什麼是錯誤狀態(返回值)tee

能夠將所有數據複製到所有輸出文件時為 0,否則為 >0。請參閱規範GNU coreutils 的實現有額外tee的選項可以在寫入管道時忽略錯誤(如那些用於實現的>(...)):

$ seq 1024 | tee >(false) >/dev/null; echo $?
141
$ seq 1024 | tee -p >(false) >/dev/null; echo $?
0

沒有選項可以知道哪些輸出失敗(如果有)

$$ 1 $$.


但是您的問題似乎是關於在>(..)程序替換中執行的命令的退出狀態是否以任何方式反映在 中PIPESTATUS,或者是否可以以任何方式反映在PIPESTATUS.

答案是否定的。

首先,請注意它>(...)更像是... &後台命令而不是...|...管道命令。在如下片段中:

... | tee >(cmd ...) | ...; echo ${PIPESTATUS[@]}

無法保證cmd在您執行時已經完成echo ${PIPESTATUS[@]}

但它們並不完全一樣...&,因為你不能wait為它們獲取它們的狀態,也不能從中獲取它們的狀態$!——除非在一些有限的情況下,它們包括它們與tee或其他外部命令的使用:

$ bash -c 'echo 1 | tee >(sleep 2; sed s/1/2/); wait; echo DONE'
1
DONE
$
<after two seconds>
2

如您所見,tee主 shell 都在>(...).

$$ 1 $$執行輸出“子命令pee”本身(並等待它們完成)的命令可能更智能,並在其退出狀態中反映其中哪些失敗(例如,通過將第 1 位設置為第一個,將第 2 位設置為第二個,等等,最多 8 個子命令),但也不做這樣的事情。

引用自:https://unix.stackexchange.com/questions/672318