2013-12-13 103 views
5

我在檢查多管道命令鏈中的某個命令是否發生錯誤時遇到問題。通常這不難檢查,但set -o pipefail和檢查${PIPESTATUS[@]}都不適用於我的情況。設置是這樣的:Bash:檢查多管道命令鏈的退出狀態

cmd="$snmpcmd $snmpargs $agent $oid | grep <grepoptions> for_stuff | cut -d',' f$fields | sed 's/ubstitute/some_other_stuff/g'" 

注意1:該命令進行了徹底測試,並完美地工作。

現在,我想將該命令的輸出存儲在名爲procdata的數組中。因此,我所做的:

declare -a procdata 
procdata=($(eval $cmd)) 

注2:eval是必要的,因爲否則$snmpcmdinvalid option -- <grepoption>錯誤,是沒有意義的,因爲<grepoption>不是$snmpcmd選項明顯拋出了。在這個階段,我認爲這是一個錯誤$snmpcmd,但這是另一個節目...

如果發生錯誤,procdata將爲空。但是,由於兩種不同的原因,它可能爲空:要麼是因爲在執行$snmpcmd時發生錯誤(例如超時),要麼是因爲grep找不到要查找的內容。問題是,我需要能夠區分這兩種情況並分別處理它們。

因此,set -o pipefail不是一個選項,因爲它會傳播任何錯誤,我無法區分哪部分管道失敗。另一方面echo ${PIPESTATUS[@]}總是0procdata=($(eval $cmd))即使我有很多管道!然而,如果我在提示符處直接執行整個命令,並立即調用echo ${PIPESTATUS[@]},它將正確返回所有管道的退出狀態。

我知道我可以將err流綁定到標準輸出,但我必須使用啓發式方法來檢查procdata中的元素是否有效或錯誤消息,並且我冒着獲得誤報的風險。我也可以將stdout管道輸入到/dev/null並只捕獲錯誤流並檢查是否${#procdata[@]} -eq 0。但我不得不重複這個呼叫來獲取實際數據,整個命令的時間成本很高(大約3-5s)。我不想打兩次電話。或者我可以使用一個臨時文件來寫錯誤,但我寧願這樣做,而沒有創建/刪除文件的開銷。

任何想法,我可以使這項工作在bash?

感謝

PS:

$ echo $BASH_VERSION 
4.2.37(1)-release 

回答

3

一些東西在這裏:

(1)當你說eval $cmd,並嘗試獲取包含在管道中的進程的出口值命令$cmd,echo "${PIPESTATUS[@]}"將包含只有退出狀態爲eval。而不是eval,你需要提供完整的命令行。 (2)將流水線的輸出分配給變量時,需要獲取PIPESTATUS。以後試圖做到這一點是行不通的。


作爲一個例子,可以說:

foo=$(command | grep something | command2; echo "${PIPESTATUS[@]})" 

此捕獲管道的輸出和PIPESTATUS陣列入變量foo

你可以說得到命令的輸出到一個數組:

result=($(head -n -1 <<< "$foo")) 

PIPESTATUS陣列說

tail -1 <<< "$foo" 
+0

我有同樣的想法。不幸的是它不起作用,但我不知道爲什麼。我發佈了確切的命令,因爲我可能看不到明顯的: – user3040975

+0

'local cmdargs =「 - CHf,-m $ mibs -v $ snmpver -c $ community $ agent」; local procdatacmd =「$ tblcmd $ cmdargs $ proc_table」; procdatacmd + =「| cut -d','-f $ fields | grep -we -e | sort | uniq -c | sed's/^ * \ | \」// g; s //,/ g' ; echo $ {PIPESTATUS [@]}「'然後執行:'declare -a procdata =($(head -n-1 <<< $ $ procdatacmd))'輸出是空的......只是沒有。 – user3040975

+0

@ user3040975你似乎沒有_running_上面的行中有任何命令 – devnull