Bash

如何在 Shell 命令中擷取 stdout 和 sterr 以及正確的管道退出狀態?

  • November 10, 2019

我希望能夠做到以下幾點:

command 2>&1 | shell_script.sh "subject line"

執行的 stdout 和 sterrcommand將通過管道傳輸到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

在這種情況下,要郵寄的數據通過標準輸入傳遞,該mail實用程序將預設讀取(就像cat在前面的範例中所做的那樣)。

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