bashでstdoutまたはファイルをエコーするエレガントなソリューション

bashでstdoutまたはファイルをエコーするエレガントなソリューション

いくつかの結果を生成する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

私は、toおよび他のものと$outfile同じ変数を持つことを試みましたが、実際にstdoutに書き込むのではなく、その名前のファイルにのみ書き込みます。よりエレガントなソリューションはありますか?stdout&1

(*) こんな目的でだまされて使うこともできますが、stderrそれも醜いと思いますか?

答え1

まず、あなたは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

これの1つの(マイナーな)欠点は、kshfd 3を除いて、スクリプトで実行されるすべてのコマンドでリークされることです。を使用すると、代わりにアクションを実行zshできますが、それに対応するアクションはありません。sysopen -wu 3 -o cloexec -- "$logfile" || exitexec 3> "$logfile"bash

別の一般的なイディオムは、次の関数を使用することです。

log() {
  if [ -n "$logfile" ]; then
    printf '%s\n' "$@" >> "$logfile"
  else
    printf '%s\n' "$@"
  fi
}

log "$buf"

答え2

  1. 設定outfile"/dev/stdout"
  2. ユーザーがファイル名を選択または上書きするか、outfileデフォルト値をそのままにします。
  3. printf '%s\n' "$outbuf" >"$outfile"

私が使うprintf理由は、「なぜprintfがechoより優れているのですか?」。

このソリューションに関する注意事項については、以下を参照してください。Stefan Chazerasの答え

答え3

この試み

#!/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

答え4

#!/bin/bash -ue

function stdout_or_file()
{
    DUMP_FILE=${1:-}

    if [ -z "${DUMP_FILE}" ]; then
        # print stdin to stdout
        cat
    else
        # dump stdin to a file
        sed -n "w ${DUMP_FILE}"
    fi
}

echo "foo" | stdout_or_file "${outfile}"

これは${1:-}bashに固有のもので、「-u」モードで特に便利です。他のシェルでも動作する一般的なシングルライナーは次のとおりです。

echo "foo" | if [ -z "${outfile}" ]; then cat; else sed -n "w ${outfile}"; fi

関連情報