
stdoutとstderrをスクリプト内からファイルと端末にリダイレクトする方法。
#!/bin/bash
LOG_FILE="/tmp/abc.log"
exec &> >(tee -a $LOG_FILE)
echo "Start"
echo "Hi" 1>&2
echo "End"
上記のスクリプトが見つかりました。ただし、このスクリプトはbashでのみ機能します。 sh シェルを使用すると、次のエラーが発生します。
./abc.sh: 5: Syntax error: redirection unexpected (expecting word)
shシェルとbashシェルで使用できるスクリプトが必要です。
答え1
はい、&>
演算子bash
(現在サポートされており、zsh
常に同じ機能をzsh
持つ)と演算子(現在およびサポートされています)はどちらも演算子ではありません。引用符のない$ LOG_FILE、ここでは明らかに分割+globを使用してzsh構文にしたくありません(この方法ではありますが、分割+globが引用符のない拡張で暗黙的に実行しない唯一のシェルです)。>&
csh
>(...)
ksh
zsh
bash
sh
zsh
exec >&1 > $LOG_FILE 2>&1
構文的には、次のようにするsh
ことができます。
#! /bin/sh -
LOG_FILE="/tmp/abc.log"
{
# your script here
} 2>&1 | tee -- "$LOG_FILE"
またはすべてを関数に入れてください:
#! /bin/sh -
LOG_FILE="/tmp/abc.log"
main() {
# your script here
}
main "$@" 2>&1 | tee -- "$LOG_FILE"
それにもかかわらず、このアプローチとzsh
-styleアプローチの両方は、標準出力で開かれた同じリソースにエラーメッセージを出力します。したがって、誰かがこれを行うと、空でyour-script > out 2> err
正常な出力とエラーが含まれます。err
out
出力とエラーの元の宛先を保存するには、次のようにします。
{
{
main "$@" 3>&- | tee -a -- "$LOG_FILE" >&3 3>&-
} 2>&1 | tee -a -- "$LOG_FILE" >&2 3>&-
} 3> "$LOG_FILE" 3>&1
(検証されていません)。
また、セキュリティの観点からは、グローバルに書き込み可能なディレクトリに固定された名前のファイルを使用するのは/tmp
悪い習慣です。他のユーザーが同じ名前の悪意のあるシンボリックリンクを配置する可能性があるため、そのリンクが指すポイントを上書きする可能性があります。文書。