一部の結果を生成しているbashアプリケーションがあり、その結果をstdout
またはユーザーが選択したファイルにエコーしたいと思います。画面に表示される他のインタラクティブメッセージもエコーするため、結果をファイルにエコーしたい場合にユーザーが>
リダイレクトを明示的に使用するように要求することはオプションではありません(*)。ファイル。
今私は解決策を持っていますが、それは醜いです。
if [ -z $outfile ]
then
echo "$outbuf" # Write output buffer to the screen (stdout)
else
echo "$outbuf" > $outfile # Write output buffer to file
fi
変数$outfile
をstdout
、&1
、およびおそらく他の何かと等しくなるようにしようとしましたが、実際にはstdoutではなく、その名前のファイルに書き込むだけでした。よりエレガントな解決策はありますか?
(*)その目的のためにstderr
をだまして使用することもできますが、それも非常に醜いと思いませんか?
まず、 任意のデータを出力するためにecho
を避ける を行う必要があります。
Linuxベース以外のシステムでは、以下を使用できます。
logfile=/dev/stdout
Linuxの場合、一部のタイプのstdoutで機能しますが、stdoutがソケットである場合、またはそれより悪い場合、stdoutが通常のファイルの場合、stdoutがファイル内の現在の位置に書き込む代わりにそのファイルを切り捨てます。
それ以外は、Bourneのようなシェルでは、eval
を使用することはできますが、条件付きリダイレクトを行う方法はありません。
eval 'printf "%s\n" "$buf" '${logfile:+'> "$logfile"'}
変数の代わりに、専用のファイル記述子を使用できます:
exec 3>&1
[ -z "$logfile" ] || exec 3> "$logfile"
printf '%s\n' "$buf" >&3
(小さな)欠点は、ksh
を除いて、fd 3がスクリプトで実行されるすべてのコマンドにリークされることです。 zsh
を使用すると、sysopen -wu 3 -o cloexec -- "$logfile" || exit
代わりに exec 3> "$logfile"
ですが、bash
には同等のものはありません。
別の一般的なイディオムは、次のような関数を使用することです。
log() {
if [ -n "$logfile" ]; then
printf '%s\n' "$@" >> "$logfile"
else
printf '%s\n' "$@"
fi
}
log "$buf"
outfile
を"/dev/stdout"
に設定します。outfile
を上書きするか、デフォルト値のままにします。printf '%s\n' "$outbuf" >"$outfile"
「 printfがechoよりも優れているのはなぜですか のため、printf
を使用しました。
このソリューションの警告については、 StéphaneChazelasの回答 を参照してください。
これを試して
#!/bin/bash
TOSCREEN="1" # empty OR 0 to log to file
if [[ ! -z "$TOSCREEN" && $TOSCREEN == "1" ]]; then
echo "$outbuf" # Write output buffer to the screen (stdout)
else
if [[ ! -f $outfile ]]; then
#echo -e "Making file "
touch "$outfile"
fi
echo "$outbuf" >> $outfile # Write output buffer to file
fi