web-dev-qa-db-ja.com

Bashスクリプト-stderrを変数に保存する

データベースをバックアップするスクリプトを書いています。次の行があります。

mysqldump --user=$dbuser --password=$dbpswd  \
   --Host=$Host $mysqldb | gzip > $filename

Stderrを変数に割り当てて、何か問題が発生した場合に何が起こったのかを知らせるメールを自分に送信するようにします。 stderrをstdoutにリダイレクトするソリューションを見つけましたが、stdoutが(gzipを介して)ファイルにすでに送信されているため、それを行うことはできません。変数$ resultにstderrを個別に格納するにはどうすればよいですか?

47
thornate

Stderrをstdoutにリダイレクトし、$()を使用してそれをキャプチャしてみてください。言い換えると:

VAR=$((your-command-including-redirect) 2>&1)

コマンドはstdoutをどこかにリダイレクトするため、stderrに干渉することはありません。より簡潔な記述方法があるかもしれませんが、それはうまくいくはずです。

編集:

これは本当に機能します。私はそれをテストしました:

#!/bin/bash                                                                                                                                                                         
BLAH=$((
(
echo out >&1
echo err >&2
) 1>log
) 2>&1)

echo "BLAH=$BLAH"

BLAH=errおよびファイルlogにはoutが含まれます。

81
Adam Crume

Bashの一般的なコマンドについては、次のようなことができます。

{ error=$(command 2>&1 1>&$out); } {out}>&1

通常の出力は正常に表示され、stderrへのすべては$ errorでキャプチャされます(改行を保持するために使用する場合は「$ error」として引用してください)。ファイルにstdoutをキャプチャするには、たとえば、最後にリダイレクトを追加します。

{ error=$(ls /etc/passwd /etc/bad 2>&1 1>&$out); } {out}>&1 >output

それを分解し、外部から読んで、それを:

  • ブロック全体のファイル記述$ outを作成し、stdoutを複製します
  • コマンド全体の標準出力を$ errorにキャプチャします(ただし、以下を参照)
  • コマンド自体はstderrをstdoutにリダイレクトし(上でキャプチャされます)、stdoutはブロックの外側から元のstdoutにリダイレクトされるため、stderrのみがキャプチャされます
18
Joat

別のファイル番号(3など)にリダイレクトされる前にstdout参照を保存してから、stderrをそれにリダイレクトできます。

result=$(mysqldump --user=$dbuser --password=$dbpswd  \
   --Host=$Host $mysqldb 3>&1 2>&3 | gzip > $filename)

そう 3>&1は、ファイル番号3をstdoutにリダイレクトします(これは、stdoutがパイプでリダイレクトされる前です)。その後、2>&3は、stderrをファイル番号3にリダイレクトします。現在はstdoutと同じです。最後に、stdoutはパイプにフィードされることでリダイレクトされますが、これはファイル番号2と3には影響しません(gzipからのstdoutのリダイレクトはmysqldumpコマンドの出力とは無関係です)。

編集:mysqldumpではなくgzipコマンドからstderrをリダイレクトするようにコマンドを更新しました。最初の答えは速すぎました。

5
hlovdal

ddは、stdoutとstderrの両方を書き込みます。

$ dd if=/dev/zero count=50 > /dev/null 
50+0 records in
50+0 records out

2つのストリームは独立しており、個別にリダイレクトできます。

$ dd if=/dev/zero count=50 2> countfile | wc -c
25600
$ cat countfile 
50+0 records in
50+0 records out
$ mail -s "countfile for you" thornate < countfile

本当に変数が必要な場合:

$ variable=`cat countfile`
0
msw