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
に書き込まれるため、出力が完全に空になるためです。
しかし、それを行う簡単な方法がなければなりませんか?
最後に引用したコマンドの理由:
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
を試してください。