web-dev-qa-db-ja.com

STDERRをSTDOUTにリダイレクトし、元のSTDOUTを無視するにはどうすればよいですか?

STDERR出力を検査して、grepなどで実行したいプログラムがあります。

したがって、STDOUTにリダイレクトしてgrepを使用できますが、問題はnot元のSTDOUTコンテンツが必要です。

だから、これはしません

cmd 2>&1 | grep pattern

元のSTDOUTとSTDERRが混在するためです。

GrepはSTDERR出力を読み取らないため、これは機能しません。

cmd 1>/dev/null | grep pattern

しかし、これも機能しません:

cmd 1>/dev/null 2>&1 | grep pattern

すべてが/dev/nullに書き込まれるため、出力が完全に空になるためです。

しかし、それを行う簡単な方法がなければなりませんか?

57
Frank

動作しないもの:

最後に引用したコマンドの理由:

cmd 1>/dev/null 2>&1 | grep pattern

動作しません。リダイレクトの動作順序の混乱に起因します。元の標準出力ファイル記述子(1)が/ dev/nullに出力され、標準エラーファイル記述子(2)に出力されるように、最後の引用されたリダイレクトがすべての出力でその前のリダイレクトに適用されると予想しました元の標準出力に移動します。

ただし、これはシェルリダイレクトの動作方法ではありません。各リダイレクトにより、「ソース」を閉じて「宛先」を複製することにより、ファイル記述子が「再マップ」されます(dup(2)およびclose(2)manページを参照) 、 順番に。これは、コマンドの標準出力が最初に/dev/nullに置き換えられ、次に標準エラーが既に/dev/nullである標準出力に置き換えられることを意味します。

動作するもの:

したがって、目的の効果を得るには、リダイレクトを逆にするだけです。次に、標準エラーを標準出力に送り、元の標準出力を/dev/nullに送ります。

cmd 2>&1 >/dev/null | grep pattern

1の前の>は不要であることに注意してください-出力のリダイレクトには、標準出力がデフォルトです)


補遺:Charlieは、ファイル記述子を閉じるために&-にリダイレクトすることを言及しました。その拡張機能をサポートするインタラクティブシェル(bashおよびその他の実装がすべてではなく、 標準ではない )を使用している場合、次のようにすることもできます。

cmd 2>&1 >&- | grep pattern

コマンドが標準出力に書き込もうとすると、カーネルへのコンテキスト切り替えとドライバーが/dev/nullを処理するのを待たずに、writeへの呼び出しがすぐに失敗する可能性があるため、これはより良いかもしれませんシステムコールの実装-libc関数でこれをキャッチする人もいれば、/dev/nullの特別な処理を持つ人もいます。価値のある出力がたくさんあり、入力する方が速い場合。

ほとんどのプログラムは標準出力(実際にprintf?の戻り値をチェックします)に書き込めないかどうかは気にせず、標準出力が閉じていることを気にしないので、これはほとんど機能します。ただし、一部のプログラムは、writeが失敗した場合、失敗コードで救済できます。通常、ブロックプロセッサ、I/O用の注意深いライブラリを使用するプログラム、または標準出力へのロギングです。うまくいかない場合は、これが原因である可能性があることを覚えて、/dev/nullを試してください。

101
Tom Alsberg

最初にSTDOUTを閉じます。

1>&-, >&-

here を参照してください。

3
Charlie Martin