Bash
如何在 Shell 命令中擷取 stdout 和 sterr 以及正確的管道退出狀態?
我希望能夠做到以下幾點:
command 2>&1 | shell_script.sh "subject line"
執行的 stdout 和 sterr
command
將通過管道傳輸到shell_script.sh
作為電子郵件正文發送的位置。我想要得到的是退出狀態,command 2>&1
以便我可以將正確的作業狀態附加到電子郵件主題。在目前實現中,當command 2>&1
通過管道傳輸時,${PIPESTATUS[0]}
始終設置為0
. 但是,如果我刪除2>&1
,則 stderr 輸出不會通過管道傳輸到電子郵件正文中。玩了幾個不同的變化,但仍然無法弄清楚。以下是我的
shell_script.sh
:#!/usr/bin/env bash SUBJ="$@" read EMAIL_BODY jobsuccess=${PIPESTATUS[0]} if [ $jobsuccess -eq 0 ] # Job succeeded then echo $EMAIL_BODY | mail -s "$SUBJ Success" my@email.com else echo $EMAIL_BODY | mail -s "$SUBJ Fail" my@email.com fi
#!/bin/bash subject="subject line" tmpfile=$(mktemp) trap 'rm -f "$tmpfile"' EXIT if command >"$tmpfile" 2>&1; then subject+=" Success" else subject+=" Failure" fi mail -s "$subject" my@email.com <"$tmpfile"
因此,將輸出保存到一個臨時文件,然後郵寄該文件。發送前根據命令的退出狀態設置主題行。不需要兩個腳本。
PIPESTATUS
由於管道尚未完成執行,您無法訪問管道內部。此外,外部腳本在任何情況下都無法訪問它,因為它在自己的環境中執行。同樣不可能的是從通用命令通過管道輸入輸入,然後對該命令的退出狀態採取行動。無法從管道本身訪問管道中先前命令的退出狀態。
您可以做的是將命令包裝在輸出一段文本的程式碼中,表示成功或失敗。該文本將與其餘數據一起通過管道傳輸(必要時,作為最後的額外資訊):
{ if command 2>&1; then echo SUCCESS; else echo FAILURE; } | shell_script.sh
…與
shell_script.sh
存在#!/bin/bash subject="subject line" tmpfile=$(mktemp) trap 'rm -f "$tmpfile"' EXIT cat >"$tmpfile" if [[ $(tail -n 1 "$tmpfile") == *SUCCESS* ]]; then subject+=" Success" else subject+=" Failure" fi sed '$d' "$tmpfile" | mail -s "$subject" me@mail.com
這仍然必須將數據保存到一個臨時文件以訪問它的最後一行(這是使用
cat
預設情況下讀取標準輸入來完成的)。然後它決定它是否成功並相應地設置主題。然後將刪除最後一行的數據郵寄。另一種選擇是在執行命令後執行郵件腳本(管道中的命令同時執行),然後簡單地將退出狀態作為命令行參數傳遞,然後該狀態將可用:
command >command.log 2>&1 shell_script.sh "$?" <command.log rm -f command.log
腳本看起來像
#!/bin/bash subject="subject line" if [[ $1 == 0 ]]; then subject+=" Success" else subject+=" Failure" fi mail -s "$subject" my@email.com
在這種情況下,要郵寄的數據通過標準輸入傳遞,該
cat
在前面的範例中所做的那樣)。