2012-10-05 31 views
7

我已經通過了一些類似的問題(如How to set a variable to the output from a command in Bash?),但是之後被接受的答案似乎不爲我工作。我不確定我是否應該脫軌別人的問題或張貼我自己的副本,所以如果我在這裏選擇了錯誤,請致歉。如何獲得bash命令的輸出變量

我希望得到一個腳本,我組建了一個數量的命令的輸出和退出狀態。這是我一直在使用什麼樣的一個例子:

cmd_output=$(rm $file) 
exit_status=$? 
if [ "${exit_status}" -eq 0 ] 
then 
log "Successfully removed the original" ${TAB_LEVEL} 
else 
fail "Failed to remove the original, the output was: \n ${cmd_output}" 
fi 

日誌和故障的功能是:

# Usage: fail "Failure message" 
function fail { 
echo "FATAL ERROR: $1" >> "${LOG_DIR}/${LOG_FILE}" 
exit 1 
} 

# Usage: log "Log message" 3 Where the tab-level is 3. 
function log { 
if (("${2}" > 0)) 
then 
eval "printf ' %.0s' {1..$2}" >> "${LOG_DIR}/${LOG_FILE}" 
fi 
echo "$1" >> "${LOG_DIR}/${LOG_FILE}" 
return 0 
} 

在上面的例子中我使用$(CMD)格式,但我自己也嘗試使用反引號。

在我的日誌文件,我看到的時候有一個失敗:

FATAL ERROR: Failed to remove the original, the output was: \n

此外,失敗的命令的輸出按通常在屏幕上結束。是否有一個共同的原因,我的cmd_output變量將保持爲空?

回答

22

你必須包括特殊標準錯誤輸出流的輸出:

cmd_output=$(rm "$file" 2>&1) 

上有每一個程序三個默認流(即編號文件描述符):

0. Standard input (where the program normally reads from) 
1. Standard output (where the program normally writes to) 
2. Standard error (where the program normally writes error messages) 

所以要捕獲錯誤消息,我們必須重定向標準錯誤輸出(錯誤)轉換成然後將由$(...)表達被捕獲正常標準輸出(stdout)。

重定向的語法是通過>「經營者」。緊接着它告訴哪個文件描述符重定向(默認值是1,這是stdout)。你可以指定它重定向到一個文件。如果在它之後寫一個和號(&),則會強制它重定向到另一個文件描述符。因此,在本例中,我們將文件描述符2(stderr)重定向到文件描述符1(stdout)。

此外,您還可以重定向與<「經營者」的輸入,但在這種情況下,默認文件描述符0(標準輸入)。

另一種看法是,它可能是很好的做法,用雙引號引你$file變量,如果它有空白字符。

希望這有助於有點=)

+1

很高興推動你超過1000分,繼續發帖! – shellter

+0

嘿Janito,非常感謝您的回答!我知道三個標準流和重定向操作符,但迄今爲止我使用它們的唯一原因是將所有內容從命令發送到/ dev/null或發送到日誌文件。我甚至沒有考慮這裏的不同流。 $ file變量實際上最初是用引號引起來的,當我測試腳本的錯誤捕捉函數時,我把它引出來,強制出錯。再次,非常感謝! –

5

* 尼克斯命令通常有兩種形式的輸出:標準輸出(stdout)和標準誤差(stderr)。

FOO=$(...)只捕獲stdout,葉子stderr不受阻礙。

如果要使用此語法的stderr的內容,則需要使用2>&1後綴來修改命令,以便stderr合併到stdout中。 (例如。像這樣:rm $file 2>&1

+0

嗨antak,只是想說一句謝謝你的答案。由於Janito的更詳細一點,我將它作爲接受的答案留下,但我非常感謝你的幫助:)。 –

0

由於您fail功能只是退出,這將是一個更容易簡單地做:

set -e # Abort on failure 
exec 2>> "${LOG_DIR}/${LOG_FILE}" # Append all errors to LOG_FILE 
if cmd_output=$(rm $file) 
    log "Successfully removed the original" ${TAB_LEVEL} 
fi 

這和原來的代碼之間的唯一區別是,它不 打印文字FATAL ERROR:。由於簡潔是一種優點,它可能會更好地完全跳過log函數。大聲報告錯誤;默默地成功 。

+0

感謝威廉。在這種情況下,我不想默默地獲得成功,但如果我正在編寫一個分發包或大多數其他目的的包,我會同意。這是內部軟件,與移動文件實際上一樣重要的是,它能夠保持非常清晰的細節(被移動的是敏感或關鍵數據)。我還需要FATAL ERROR前綴 - 日誌文件由機器運行,數據被複制到尋找那個或幾個其他行前綴。 雖然再次感謝! –