現在、次の設定を使用して複数のコマンドの出力をリダイレクトしています。
echo "Some normal commands"
(
echo "Error: something happened"
echo "Warning: this incident will be logged"
) >> logfile
echo "More normal commands"
これはかなり便利で、パイプでも機能します。
これはこれを行う最良の方法ですか?考慮すべき代替案はありますか?
:)
現在、次の設定を使用して複数のコマンドの出力をリダイレクトしています。
echo "Some normal commands"
(
echo "Error: something happened"
echo "Warning: this incident will be logged"
) >> logfile
echo "More normal commands"
これはかなり便利で、パイプでも機能します。
これはこれを行う最良の方法ですか?考慮すべき代替案はありますか?
:)
回答:
代わりに、括弧の代わりに中括弧を使用することもできます。この変更により、サブシェルではなく現在のシェルでコマンドが実行されます
echo "Some normal commands"
{
echo "Error: something happened"
echo "Warning: this incident will be logged"
} >> logfile
echo "More normal commands"
ref:https : //www.gnu.org/software/bash/manual/bashref.html#Command-Grouping
これは、グループ内の変数を変更する場合に特に関係があります。
$ x=5; ( x=10; echo inside: $x; ); echo outside: $x
inside: 10
outside: 5
$ x=5; { x=10; echo inside: $x; }; echo outside: $x
inside: 10
outside: 10
{ }
ただし、そうではありません( )
。)
(echo msg1; echo msg2)
–ただし、中かっこを使用する場合は{ echo msg1; echo msg2;}
、の後にスペース{
を入れ、セミコロン(;
)またはアンパサンド(&
)の前に置く必要があり}
ます。
グレンの答えは良いものです-の区別( ... )
と{ ... }
が重要です。
あなたの質問にあるようなエラー出力によく使用する1つの戦略は、tee
コマンドです。あなたはこのようなことをすることができます:
echo "Normal output"
{
printf "[%s] %s\n" "$(date '+%Y-%m-%d %T')" "Warning text"
printf "[%s] %s\n" "$(date '+%Y-%m-%d %T')" "This event is logged."
} | tee -a $logfile >&2
echo "More normal output"
tee
コマンドは、2つの場所に出力を送信します。-a
オプションは、指定されたファイルに出力を「追加」し、コマンドは入力をstdoutに渡します。>&2
ラインリダイレクトの終了時にtee
(すなわち、cronジョブに)異なる方法で処理することができる標準エラーへのSTDOUT、。
シェルスクリプトでよく使用するもう1つのヒントは、スクリプトが端末で実行されているか、-v
オプションが提供されているかに基づいて、デバッグまたは詳細出力の動作を変更することです。例えば:
#!/bin/sh
# Set defaults
if [ -t 0 ]; then
Verbose=true; vflag="-v"
else
Verbose=false; vflag=""
fi
Debug=false; AskYN=true; Doit=true
# Detect options (altering defaults)
while getopts vdqbn opt; do
case "$opt" in
v) Verbose=true; vflag="-v" ;; # Verbose mode
d) Debug=true; Verbose=true; vflag="-v" ;; # Very Verbose
q) Verbose=false; vflag="" ;; # quiet mode (non-verbose)
b) AskYN=false ;; # batch mode
n) Doit=false ;; # test mode
*) usage; exit 1 ;;
esac
done
# Shift our options for further processing
shift $(($OPTIND - 1))
$Verbose && echo "INFO: Verbose output is turned on." >&2
$Debug && echo "INFO: In fact, expect to be overrun." >&2
# Do your thing here
if $AskYN; then
read -p "Continue? " choice
case "$choice" in
Y|y) $Doit && somecommand ;;
*) echo "Done." ;;
esac
fi
スクリプトは、このような一般的なものから始め、VerboseとDebugの出力がスクリプト全体に散らばっています。それはそれを行うための1つの方法にすぎません-多くの人がいて、さまざまな人々がすべてこのことを処理するための独自の方法を持っています(特に、彼らがしばらくの間いた場合)。:)
もう1つのオプションは、出力を「ハンドラー」で処理することです。これは、よりインテリジェントな処理を行うシェル関数です。例えば:
#!/bin/bash
logme() {
case "${1^^}" in
[IN]*) level=notice ;;
W*) level=warning ;;
A*) level=alert ;;
E*) level=emerg ;;
*) level=notice ;;
esac
if [[ "$#" -eq 1 ]]; then
# Strip off unnecessary prefixes like "INFO:"
string="${1#+([A-Z])?(:) }"
else
shift
string="$@"
fi
logger -p "${facility}.${level}" -t "$(hostname -s)" "$string"
}
echo "Normal output"
logme INFO "Here we go..."
somecommand | logme
echo "Additional normal output"
(これ${var^^}
はbashのみであることに注意してください。)
これにより、システムのsyslog
関数を使用できるシェル関数が作成されます(logger
コマンド) to send things to system logs. The
logme() `関数を使用すると、ログデータの1行を生成するオプション、またはstdinで処理される複数行の入力を使用できます。魅力的だ。
これは一例であり、理解し、必要なことを正確に行うことがわかっている場合を除いて、そのままコピーしないでください。より良いアイデアは、ここで概念を取り、独自のスクリプトでそれらを自分で実装することです。
function log () { cat >> $logfile }
、これは基本的にはのより単純なバージョンですlogme
。
ts(1)
。使用法:{ printf '%s\n' "Warning text"; printf '%s\n' "This event will be logged"; } | ts '[%Y-%m-%d %T]' | tee -a "$logfile" >&2
。
ts(1)
私が使用しているシステム(FreeBSD、OSX、古いUbuntuボックス)にはインストールされていません。それを提供するものを教えていただけますか?
sponge(1)
(stdinが閉じられた後にのみファイルに書き込むため、リダイレクトによるsomething < foo | sponge foo
クローバなしで実行できるfoo
)やvipe(1)
(テキストエディターをパイプに挿入する)などの便利なツールも含まれています。
これを行うより適切な方法は、{ command; }
ではなくを使用すること(command)
です。その理由は、コマンドが()
サブシェルでグループ化されると、それらのコマンドを実行するために開かれるため、そのブロック中に初期化された変数は、スクリプトの他のセクションで使用できないためです。
代わりに{}
、コマンドのグループ化に使用する場合、コマンドは同じシェル内で実行されるため、スクリプトの他のセクションで変数を使用できます。
echo "Some normal commands"
{
var=1
echo "Error: something happened"
echo "Warning: this incident will be logged"
} >> logfile
echo "The value of var is: $var"
echo "More normal commands"
ここで、このセクションが実行されると、$var
変数はその値を保持しますが、他の場合とは異なります。
{ command; }
。