如何將 stdout 儲存到檔案、stderr 儲存到檔案、stdout+stderr 儲存到檔案以及將 stdout + stderr 儲存到終端,就像 shell 腳本的正常情況一樣

如何將 stdout 儲存到檔案、stderr 儲存到檔案、stdout+stderr 儲存到檔案以及將 stdout + stderr 儲存到終端,就像 shell 腳本的正常情況一樣

如何將 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避免這種副作用。在標準錯誤之前重定向標準輸出也會將每個錯誤傳送到stdoutstdall

由於 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,並且應用程式應該決定如何處理訊息。

相關內容