如何將 stdout 儲存到一個文件,將 stderr 儲存到另一個文件,將 stdout+stderr 儲存到第三個文件,並像 shell 腳本一樣將 stdout + stderr 儲存到終端?
我在其他地方找到了這個:
exec > >(tee std_out) 2> >(tee err_out >&2)
ls # Should got to std_out
fsdfs # Command not found goes to err_out
這真的很接近。如果我運行,bash test.sh 2>&1 | tee output
那麼它可以工作,但我無法存取我的腳本的運行方式。這是一個cid系統。我需要能夠使用 exec 從腳本內部執行“組合輸出”。
我正在創建一個 CI/CD 庫,但我無法知道客戶將使用該庫做什麼,因此我想考慮每個用例。
答案1
簡單地擴展你的方法:
exec 2> >(tee -a stderr stdall) 1> >(tee -a stdout stdall)
標準錯誤將寫入名為 的文件stderr
,標準輸出為stdout
,標準錯誤和標準輸出也將被寫入控制台(或exec
運行時兩個文件描述符所指向的任何內容)和stdall
。
tee -a
(append) 是必需的,以防止被開始寫入的stdall
第二個資料覆蓋。tee
注意命令其中執行重定向是相關的:第二個進程替換受到第一個重定向的影響,即它發出的錯誤將被發送到>(tee -a stderr stdall)
.當然,您可以將第二個進程替換的標準錯誤重新導向到 以/dev/null
避免這種副作用。在標準錯誤之前重定向標準輸出也會將每個錯誤傳送到stdout
和stdall
。
由於 Bash 進程替換中的命令被執行非同步地,無法保證它們的輸出將按照產生的順序顯示。更糟的是,標準輸出和標準錯誤的片段最終可能出現在同一行。
答案2
$0
您的腳本可以透過(透過設定和檢查環境變數以避免無限遞歸)自行運行,而不是依賴 bash 的> >(...)
構造,而 IMLE 的構造是反覆無常且不可靠的。
if [ "$REDIRECTED" != 1 ]; then
export REDIRECTED=1
set -o pipefail
{ { "$0" | tee stdout >&3; } 2>&1 | tee stderr; } 3>&1 | tee stdboth
exit
fi
# rest of your script here
由於tee
不使用行緩衝(也不能使用 強制這樣做stdbuf(1)
),因此最終輸出中將不考慮寫入 stdout 和 stderr 的資料順序。對於使用完全緩衝並同時寫入 stdout 和 stderr 的命令,即使行緩衝也tee
無濟於事,更糟糕的是,您可能會得到一半 stdout 和一半 stderr 的輸出行。
我認為僅使用 shell 語言和現成的命令列實用程式無法解決此問題。
答案3
我正在創建一個 CI/CD 庫,但我無法知道客戶將使用該庫做什麼,因此我想考慮每個用例。
鑑於這種情況,我質疑 bash 是否需要處理輸出。理想情況下,在這種情況下,您需要對輸出添加時間戳記並為其提供標準輸出類型的 id,並且應用程式應該決定如何處理訊息。