スクリプト出力のリダイレクトとログ


8

次のスニペットを整理しようとしています。設計目標は、スクリプトからのすべての出力をログに記録することであり、ラッパーであってはなりません。線が少ないほど良いです。

(この段階では)ユーザー入力は気にしません。ターゲットスクリプトは非対話的に実行されます。

スニペットは

  • ログにstdoutを出力し、常にコンソールにエコーする
  • ログにstderrを出力し、デバッグが有効な場合はコンソールにエコー
  • stderrメッセージには、タイムスタンプとその他の有用性をプレフィックスとして付ける必要があります

現時点では、Ubuntuのように最近のバージョンのbash(4.2以降?)でのみテストできますが、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プロシージャの1つを呼び出すことができますmsg_con "hello world"
また、スクリプトの出力は、呼び出し時に環境変数として設定することにより、stderrに送られます  DEBUG_TEST=true myscript

私は、execがbusyboxなどの一部のシェルで機能しない可能性があることを読みました。https://stackoverflow.com/a/5200754に mkfifoとforkの組み合わせがあります。これは同様のことを行いますが、絶対に必要な場合を除いて、forkは使用しません。

bashの例をお勧めしますが、shの下で動作するか、より移植性の高いものが良いでしょう。何か案は?

回答:


1
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を何かに設定する必要があります


これはちょっとクールです。私が読んでいる方法では、gawkを使用してメッセージヘッダーを追加します。これには、コマンド出力にそれらを追加するという追加の副作用があります。
Glenn

gawkを使用して各ログ行にタイムスタンプ(およびプロセスID)を追加する理由は、出力が書き込まれるたびに実行され、タイムスタンプが更新されるためです。また、strftime関数はGNU拡張機能だと思うので、awkではなくgawkを使用することも重要です。
アンジェロ

0

exec > filenameshで動作するはずですが、実際には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}

スクリプトを手動で呼び出して出力を確認する場合は、リダイレクトせずに呼び出します。


1
質問者は、スクリプトの出力がコンソールとログファイルの両方に移動することを望んでいます。

0

これらの2つの例は、指定された目的を実行します

echo -n $(date) >> $DEBUG_LOG
command 2>&1 | tee -a $DEBUG_LOG

または

echo -n $(date) >> $DEBUG_LOG
command >> $DEBUG_LOG 2>&1

0

teeコマンドを使用することscriptも、両方を使用することもできます。


スクリプトはクールに見えますが、実際に私が必要とすることはしていません。動作は実行時に変更可能でなければなりません。
Glenn
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.