Bash

重定向和記錄腳本輸出

  • December 19, 2018

我正在嘗試整理以下片段,設計目標是記錄腳本的所有輸出,而不應該是包裝器。線越少越好。

我不關心使用者輸入(在這個階段),目標腳本以非互動方式執行。

片段需要

  • 將標準輸出輸出到日誌,並始終回顯到控制台
  • 如果啟用了調試,則輸出 stderr 到日誌,並回顯到控制台
  • stderr 消息應以時間戳和其他用途為前綴

目前我有以下僅在最新版本的 bash(4.2+?)下測試,就像在 Ubuntu 中一樣精確,但在 CentOS6 上行為不端。

DEBUG_LOG="${0##*/}.log"

# copy stdout to log always and echo to console
exec >  >(tee -a ${DEBUG_LOG})           

# copy stderr to log only, unless debugging is enabled
[ $DEBUG_TEST = "true" ] \
 && exec 2> >(tee -a ${DEBUG_LOG} >&2) \
 || exec 2>> ${DEBUG_LOG}

那麼這個…

# Expand escaped characters, wrap at 70 chars on spaces, 
# and indent wrapped lines
msg_log() { 
 echo -e "$(date +%T) ${0##*/}: $1" \
   | fold -w70 -s | sed '2~1s/^/  /' >&2; 
}
msg_con() { 
 if [ "${DEBUG_TEST}" = "true" ]; then 
   msg_log "$1"
 else
   echo -e "$1" | fold -w70 -s | sed '2~1s/^/  /'; 
 fi
}

而不是echo我可以呼叫這些 msg 過程之一,例如msg_con "hello world".

此外,腳本輸出將通過在呼叫時設置為環境變數(例如 DEBUG_TEST=true myscript.

我已經讀過 exec 可能無法在某些 shell(例如busybox)中工作。在https://stackoverflow.com/a/5200754有一個 mkfifo 和 fork 組合可以做類似的事情,但除非絕對需要,否則我寧願不使用 fork。

請首選 bash 範例,但是在 sh 下工作或更便攜的東西會很好。有任何想法嗎?

function startLogging {
   exec > >(gawk -v pid=$$ '{ print strftime("%F-%T"),pid,$0; fflush(); }' | tee -a $logfile)
   [ ! -z "$DEBUG" ] && exec 2>&1 || exec 2> >(gawk -v pid=$$ '{ print strftime("%F-%T"),pid,$0; fflush(); }' >>$logfile)
   echo "=== Log started for $$ at $(date +%F-%T) ==="
}

您需要將 $logfile 設置為

exec > filename應該在 sh 中工作,它實際上在busybox v1.15.3(2011 年 11 月)中工作。但是程序替換>(command)是不可移植的,因為它是 bash 擴展。只是避免在腳本中使用它。為什麼>>對你來說還不夠?

exec 1>>${DEBUG_LOG}
exec 2>>${DEBUG_LOG}

另一種解決方案是在腳本之外指定重定向。當您的腳本在後台呼叫時(通過 cron 或系統腳本等),它們應該像這樣呼叫

./my_script 1>>${DEBUG_LOG} 2>>${DEBUG_LOG}

當您手動呼叫腳本並且想要查看輸出時,只需呼叫它而不進行重定向。

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