web-dev-qa-db-ja.com

標準出力ではなく標準エラー出力をパイプ処理する方法

私はstdoutstderrに情報を書き込むプログラムを持っています、そして stdout を無視しながら stderr に来るものを通してgrepにする必要があります。

私はもちろん2つのステップでそれをすることができます:

command > /dev/null 2> temp.file
grep 'something' temp.file

しかし、一時ファイルがなくてもこれを実行できるようにしたいと思います。スマートな配管工法はありますか?

867
user80168

最初に標準エラー出力を標準出力にリダイレクトします - パイプ。次にstdoutを/dev/nullにリダイレクトします(stderrの行き先を変更せずに)。

command 2>&1 >/dev/null | grep 'something'

あらゆる種類のI/Oリダイレクトの詳細については、Bashリファレンスマニュアルの リダイレクト の章を参照してください。

I/Oリダイレクトの順序は左から右に解釈されますが、パイプはI/Oリダイレクトが解釈される前に設定されます。 1や2などのファイル記述子は、開いているファイルの説明への参照です。操作2>&1は、ファイル記述子2、つまり標準エラー出力を現在記述しているファイル記述子1と同じオープンファイル記述を参照させます( dup2() および open() を参照)。その後、オペレーション>/dev/nullは、ファイル記述子1が/dev/nullのオープンファイル記述を参照するようにファイル記述子1を変更しますが、ファイル記述子2がファイル記述子1が最初に指していたオープンファイル記述を参照するという事実は変わりません。パイプ。

1035

あるいは、stderrとstdoutからの出力を使いすぎに交換するには: -

command 3>&1 1>&2 2>&3

これは新しいファイル記述子(3)を作成し、それを1(stdout)と同じ場所に割り当て、次にfd 2(stderr)と同じ場所にfd 1(stdout)を割り当て、最後に同じファイルにfd 2(stderr)を割り当てます。 FD 3(stdout)として配置します。標準エラー出力と標準エラー出力が標準エラー出力に保存されるようになりました。これはやり過ぎるかもしれませんが、うまくいけばbashファイル記述子についてより多くの詳細を与えます(各プロセスに利用可能な9があります)。

329
Kramish

Bashでは、 プロセス置換 を使用してサブシェルにリダイレクトすることもできます。

command > >(stdlog pipe)  2> >(stderr pipe)

当面の場合:

command 2> >(grep 'something') >/dev/null
193
Rich Johnson

あなたがするならば、これらの答えのベストを組み合わせる:

command 2> >(grep -v something 1>&2)

...そしてすべての標準出力は標準出力として保持されます および - すべての標準エラー出力は標準エラー出力として保持されますが、文字列 "something"を含む標準エラー出力内の行は表示されません。

これには、stdoutとstderrを元に戻したり破棄したり、まとめて平滑化したり、一時ファイルを使用したりしないという独自の利点があります。

166
Pinko

実際に何が起こっているのかを「リダイレクト」と「パイプ」で考えると、物事を視覚化する方がはるかに簡単です。 bash内のリダイレクトとパイプは1つのことを行います。プロセスファイル記述子0、1、および2が指す場所を変更します(/ proc/[pid]/fd/*を参照)。

パイプ または "|"の場合operatorがコマンドラインに存在する場合、最初に起こることは、bashがfifoを作成し、左側のコマンドのFD 1をこのFIFOに向け、右側のコマンドのFD 0を同じfifoに向けます。

次に、各サイドのリダイレクト演算子が 左から右へ と評価され、記述子が重複するたびに現在の設定が使用されます。これは、パイプが最初にセットアップされてから、FD1(左側)とFD0(右側)が通常の状態から既に変更されており、これらの複製がその事実を反映するためです。

したがって、次のように入力したとします。

command 2>&1 >/dev/null | grep 'something'

これが起こる順序は、次のとおりです。

  1. パイプ(fifo)が作成されます。 「command FD1」はこのパイプを指しています。 "grep FD0"もこのパイプを指しています
  2. 「command FD2」は「command FD1」が現在指している場所(パイプ)を指しています
  3. "command FD1"は/ dev/nullを指しています

そのため、 "command"がそのFD 2(stderr)に書き込むすべての出力はパイプに進み、反対側の "grep"によって読み取られます。 「command」がそのFD 1(stdout)に書き込むすべての出力は、/ dev/nullになります。

代わりに、次のように実行します。

command >/dev/null 2>&1 | grep 'something'

これが起こるのです:

  1. パイプが作成され、「command FD 1」と「grep FD 0」がポイントされている
  2. "command FD 1"は/ dev/nullを指しています
  3. "command FD 2"は、FD 1が現在指している場所を指しています(/ dev/null)。

そのため、 "command"からのすべての標準出力と標準エラー出力は/ dev/nullになります。パイプには何も行きません。したがって、 "grep"は画面に何も表示せずに閉じます。

リダイレクト(ファイル記述子)は、読み取り専用(<)、書き込み専用(>)、または読み取り/書き込み(<>)のいずれかです。

最後のメモプログラムがFD1に書き込むかFD2に書き込むかは、完全にプログラマ次第です。良いプログラミング方法はエラーメッセージをFD 2に、通常の出力をFD 1に出力するように指示しますが、2つを混ぜ合わせるか、そうでなければ規約を無視するずさんなプログラミングを見つけるでしょう。

92

あなたはbashを使っていますか?もしそうなら:

command >/dev/null |& grep "something"

http://www.gnu.org/software/bash/manual/bashref.html#Pipelines

30
Ken Sharp

Stdoutとstderrを永続的にファイルにリダイレクトしたい人は、stderrをgrepしてください。

# save tty-stdout to fd 3
exec 3>&1
# switch stdout and stderr, grep (-v) stderr for nasty messages and append to files
exec 2> >(grep -v "nasty_msg" >> std.err) >> std.out
# goes to the std.out
echo "my first message" >&1
# goes to the std.err
echo "a error message" >&2
# goes nowhere
echo "this nasty_msg won't appear anywhere" >&2
# goes to the tty
echo "a message on the terminal" >&3
9
JBD

これはcommand1 stdrをそのままcommand2 stdinにリダイレクトします。

exec 3>&1
command1 2>&1 >&3 3>&- | command2 3>&-
exec 3>&-

_ ldp _ から撮影

5
theDolphin

名前付きパイプを使用して、あるコマンドにstdoutを送信し、別のコマンドにstderrを送信するためのソリューションを思いついたのです。

ここに行きます。

mkfifo stdout-target
mkfifo stderr-target
cat < stdout-target | command-for-stdout &
cat < stderr-target | command-for-stderr &
main-command 1>stdout-target 2>stderr-target

後で名前付きパイプを削除するのはおそらく良い考えです。

1
Tripp Kinetics

rcシェル を使用できます。

最初にパッケージをインストールします(1MB以下です)。

これは、stdoutを破棄し、stderrのgrepにパイプ処理するrcの例です。

find /proc/ >[1] /dev/null |[2] grep task

Bashを離れることなくそれを実行できます。

rc -c 'find /proc/ >[1] /dev/null |[2] grep task'

お気づきかもしれませんが、パイプの後に大括弧を使用して、パイプ処理するファイル記述子を指定できます。

標準ファイル記述子は、次のように数値化されています。

  • 0:標準入力
  • 1:標準アウトプット
  • 2:標準エラー
0
Rolf