web-dev-qa-db-ja.com

変数でstderrをリダイレクトし、コンソールでstdoutを保持する方法

私の目標は、コマンドを呼び出し、変数にstderrを取得することですが、stdout(およびstdoutのみ)を画面に表示したままにします。うん、それはほとんどの人がすることの反対です:)

今のところ、私が持っている最高のものは:

#!/bin/bash
pull=$(Sudo ./pull "${TAG}" 2>&1)
pull_code=$?

if [[ ! "${pull_code}" -eq 0 ]]; then
  error "[${pull_code}] ${pull}"
  exit "${E_PULL_FAILED}"
fi

echo "${pull}"

ただし、これは、成功した場合、およびコマンドの終了後にのみ標準出力を表示できます。 stdoutをライブで使用したいのですが、これは可能ですか?

[〜#〜]編集[〜#〜]

@sebasthのおかげで、そして STDERRとSTDOUTを一時ファイルなしで別の変数にリダイレクトする の助けを借りて、私はこれを書きます:

#!/bin/bash
{
  Sudo ./pull "${TAG}" 2> /dev/fd/3
  pull_code=$?
  if [[ ! "${pull_code}" -eq 0 ]]; then
    echo "[${pull_code}] $(cat<&3)"
    exit "${E_PULL_FAILED}"
  fi
} 3<<EOF
EOF

私はこれが本当に「きれい」ではないことを認め、トリッキーに見えますが、なぜヘレドックが必要なのか本当にわかりません...

これはそれを達成するためのより良い方法ですか?

4
Doubidou

ただ使う:

{ err=$(cmd 2>&1 >&3 3>&-); } 3>&1

Stdoutを変更せずにcmdのstderrを取得するには(ここではfd 3を使用してbringコマンド置換内の元のstdout(3>&1でコピー))( >&3は、2>&1)を使用したコマンド置換によって作成されたパイプにfd 2をリダイレクトした後です。

7

StéphaneChazelas が提供する回答を少し変更して使用できます。stderrのみをリダイレクトし、コマンド置換を使用してコマンドを実行しないでください。

{
  command 2> /dev/fd/3
  res=$?
  err=$(cat<&3)
} 3<<EOF
EOF

printf 'stderr: %s\n' "$err"

commandの出力は通常stdoutにあり、stderrはerr変数にあります。

3
sebasth

Stdrをキャプチャするコマンドのstdoutとstderrを交換するだけです。

pull=$(Sudo ./pull "${TAG}" 3>&2 2>&1 1>&3)

そして、stderrをstdoutにリダイレクトします。

{ pull=$(Sudo ./pull "${TAG}" 3>&2 2>&1 1>&3; } 2>&1

説明:

コマンドのstdoutのみをキャプチャする場合と同じ方法で:

var=$(cmd)

stderrの出力は引き続きコマンドラインに送られます。両方のチャネルを交換して、stderrのみをキャプチャできます。

var=$(cmd 3>&2 2>&1 1>&3)

次に、stderrをstdoutにリダイレクトします(出力がある場合)。

{ var=$(f 3>&2 2>&1 1>&3); }  2>&1
1
Isaac

両方からの回答を組み合わせる スクリーンオーバーライドリダイレクトに出力する方法 および bashキーワードのstderrをキャプチャする方法(時間など)?

var=$( (cmd >/dev/tty) 2>&1)

組み込みまたはキーワードを使用していない場合は、

var=$( cmd 2>&1 >/dev/tty )
1
JigglyNaga