私はしばしば次の簡単なコマンドのためにイライラしています。
find / | fgrep somestuff.ext
使用しないと、sudo
権限が拒否された行が引き続き表示されます。これは公平ですが、grepがパイプから読み取ったときにこの出力が無視されないのはなぜですか?
この形式の出力がパイプに渡されるのではなく、ターミナルウィンドウに直接送信され(これが起こったと思われる)、その後grepによって無視されるのはなぜですか? catによって同じ行が生成されますが(許可拒否メッセージが保存されていると仮定)text)ファイルはパイプに正しく入り、私のgrepパターンでは無視されますか?
STDIN / STDOUTプロセスに私が理解していないものがあるようです。
答え1
許可拒否メッセージは、stdoutではなくfind
stderrに送信されます。 stderr全体をビットバケットにリダイレクトできます。
find 2>/dev/null | fgrep somestuff.ext
また、特定のファイルを見つけるためにgrepは必要ありません。
find . -name somestuff.ext
それでも申請できます2>/dev/null
。
許可拒否メッセージのみを表示したくない場合は、次のものを使用できます。
2> >(grep -v 'Permission denied' >&2)
バッシュから。
答え2
nemocaの良い答えこの問題を解決しながら発見した動作の理由は、bashの基本的なパイプ動作です(そしてほとんどのシェルでも想像しています)。
パイプラインのセクションで述べたようにman bash
:
コマンドの標準出力はコマンド2の標準入力にパイプされます。この接続は、コマンドで指定されたリダイレクトの前に行われます(以下のリダイレクトを参照)。
これは、stderrリンクが基本的stderr
にパイプを介して供給されず、デフォルトのstderrリンクであるttyに駆動されることを意味します。command1
command2
Bashのマニュアルには次のように記載されています。
|&を使用すると、コマンドの標準エラーは、標準出力に加えてcommand2の標準入力にパイプされます。これは2>&1 |の略です。
したがって、あなたの場合、grepコマンドにパイプするには、デフォルトで送信される/dev/stderr
findコマンドエラーは、次の2つの形式のいずれかでなければなりません。
find / |& fgrep somestuff.ext
find / 2>&1 | fgrep somestuff.ext
質問のタイトルは、「パイプが標準エラーを無視する理由」かもしれません。
答えは、bashとLinuxがstdout
デフォルトでこれを異なる方法で処理し、stderr
ユーザーが2つの出力を異なる方法で記録/処理できるからです。
たとえば、stdout
コマンド1をstdin
コマンド2にパイプし、stderr
.を使用してコマンド1をログファイルに送信できます2>errorlog.txt
。
実際、次のようにリダイレクトを指定せずにコマンドを実行すると、
find /
それは等しい
find / 1>/dev/stdout 2>/dev/stderr
最終的な解決策は次のとおりです。
find / 1>/dev/tty1 2>/dev/tty1 #assuming that you are logged in tty1
単一の検証が可能ですls
。
ls -all /dev/st*
lrwxrwxrwx 1 root root 15 Nov 25 15:36 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root 15 Nov 25 15:36 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx 1 root root 15 Nov 25 15:36 /dev/stdout -> /proc/self/fd/1
ls -all /proc/self/fd/2
lrwx------ 1 root root 64 Nov 28 02:46 /proc/self/fd/2 -> /dev/tty1
ls -all /proc/self/fd/1
lrwx------ 1 root root 64 Nov 28 02:46 /proc/self/fd/1 -> /dev/tty1
何らかの理由でstdout
コマンドを「結合」するには(パイプの場合)または(すべての種類の出力リダイレクトの場合)、使用目的を明示的に宣言する必要がstderr
あります。bash
|&
2>&1