> /dev/null 2>&1はどのように機能しますか? [コピー]

> /dev/null 2>&1はどのように機能しますか? [コピー]

> /dev/null出力をリダイレクトすると、画面に印刷されない理由がわかります。

しかし、何らかの理由でこれだけでは十分ではなく、まだ何かが印刷されます。

この場合、> /dev/null 2>&1期待される結果が達成されます。

しかし、これは私を少し混乱させます。誰かがこれがどのように機能するかを詳しく説明できますか?

この部分は特に混乱しています&1。それを見ると&「バックグラウンドで実行される」という気がする。 1がどういう意味なのかはわかりませんが、2ならどうでしょうか?

答え1

シェルで実行されるプログラムは3つのストリームを取得します。

0 - standard input [stdin]
1 - standard output [stdout]
2 - standard error (output) [stderr]

キーボードのように考えることができますstdin(単純化してパイプやリダイレクトはありません)。

その後、画面に何かを印刷するために、各プログラムは標準出力または標準エラーに書き込むことができます。通常、通常の出力はに行き、stdoutエラー出力はに移動しますstderr

リダイレクトすると、>標準出力のみがリダイレクトされます。あなたが使用できる1>

リダイレクトすると、2>stderrだけがリダイレクトされます。

したがって、プログラムが何かを印刷してstderr次のことを行う場合:

program > /dev/null

あなたはそれを見ることができます。

stderr出力を表示したくない場合は、リダイレクトとstdoutリダイレクトという2つ以上のソリューションがあります。stderr/dev/null

program > /dev/null 2>/dev/null

または、あなたの質問に対する答えは次のとおりです。stderrにリダイレクトされ、lstdoutにリダイレクトされました。/dev/nul

program > /dev/null 2>&1

これは Bash が右から左に2>&1読んでいるので、最後にあります。stderrstdout

答え2

I/O リダイレクトの複雑さを理解するには時間がかかります。主なポイントは次のとおりです。

  1. ファイル記述子番号などは、、、mなどのような変数であるか、、、、...のような配列へのインデックスであります012xyzfd[0]fd[1]fd[2]
  2. リダイレクト演算子<、、、>および>><&>&これらの変数に値を割り当てる演算子です。
  3. これらの割り当ては、コマンドラインから左から右に厳密に行われます。今後コマンドは、コマンドラインに表示される場所に関係なく実行されます。
  4. ファイル記述子番号が左から省略された場合、デフォルト値が存在するか、0少なくとも最初の3つの演算子の値があります。1

これだけでは問題を完全にはっきりと説明できないので、いくつかの例を挙げて説明します。


cmd arg arg arg。これには明示的なリダイレクトはありませんが、この簡単な例はシェルがどのように実行するかについて基本的なプロセスを設定するのに役立ちます。では、ここで何が起こっているのでしょうか?

  1. シェルは新しいプロセスを分岐し、シェルでコードを実行し続け、最終的には実行されますが、cmdまだ実行されません。ここからすべてが新しいプロセスで発生します。
  2. デフォルトのI / Oリダイレクト設定:これは明示的なリダイレクトとほぼ同じです0</dev/tty 1>/dev/tty 2>/dev/tty
  3. このプロセスでは、コマンドラインのすべての明示的なリダイレクトが処理され、既に設定されているデフォルトの割り当てが変更される可能性があります。
  4. cmd arg arg arg設定されたファイル記述子の接続を維持しながら、分岐プロセスで実行されます。 (これはexecさまざまなシステムコールを介して行われます。)

だから、だから何cmd arg arg arg >file

  1. 新しいプロセスをフォークし、デフォルトのファイル記述子割り当てを設定します。
  2. 最初の明示的なリダイレクトが見つかりました>file
    • 同等ですが珍しい形式に変換してください1>file
    • 出力を開き、fileファイル記述子に追加します1。これは、前のステップ(1)で行われたstdoutのデフォルト割り当てを上書きします。
  3. cmd arg arg arg同じプロセスで実行します。ファイル記述子1が変更され、stdoutfileはこの端末を置き換えます。

しかし、今は多くの出力を得て、それをファイルに保存するのではなく、単に捨てたいとしましょう。まあ、私たちはcmd arg arg arg>/dev/null

  • これは正確に/dev/null が供給しようとしているすべてのバイトを受け入れ、次に破棄することは常に存在するマジックファイルであることを除いて、上記の例とすべての点で同じです。

まあ、まだ多くの出力が表示されます。上記のリダイレクトで問題が解決しないのはなぜですか?特に、歴史的に多くのUNIXコマンドは、通常の出力とエラー出力を分離しました。前者はstdout(ファイル記述子1)に移動し、後者はstderr(ファイル記述子2)に移動します。これは一般的に便利ですが、マブソサ、出力が消えたくなるだけです。

あなたの仕事は何ですか?さて、何とかstderrに送信されたすべてのバイトを/ dev / nullに再割り当て(リダイレクト)する必要があります。いいですね。次は動作します。

cmd arg arg arg >/dev/null 2>/dev/null

(この質問は最初に要求された質問ではありません。まもなく出てくるでしょう。

さて、ここで何が起こっているのでしょうか?

  1. いつものように、新しいプロセスをフォークし、デフォルトのファイル記述子割り当てを設定します。
  2. 最初の明示的なリダイレクトが見つかりました>/dev/null
    • 同等ですが珍しい形式に変換してください1>/dev/null
    • 出力を開き、/dev/nullファイル記述子に追加します1。これは、前のステップ(1)で行われたstdoutのデフォルト割り当てを上書きします。
  3. 次の明示的なリダイレクトを参照してください2>/dev/null
    • 出力用に開き、開いた/dev/nullファイルをファイル記述子に追加します2。これにより、記述子に添付されている元のファイルが上書きされます2
  4. cmd arg arg arg同じプロセスで実行します。ファイル記述子は1デフォルト2設定で変更されました。

2つの別々の開口部があることを認識することが重要です/dev/null。ファイル記述子12./dev/null を通常のファイル名に置き換えてファイルのすべての出力をキャプチャしようとすると、問題が発生する可能性があります。


最後に、実際にリクエストしたフォームです。

cmd arg arg arg >/dev/null 2>&1

  1. いつものように、新しいプロセスをフォークし、デフォルトのファイル記述子割り当てを設定します。
  2. 最初の明示的なリダイレクトが見つかりました>/dev/null
    • 同等ですが珍しい形式に変換してください1>/dev/null
    • 出力を開き、/dev/nullファイル記述子に追加します1。これは、前のステップ(1)で行われたstdoutのデフォルト割り当てを上書きします。
  3. 次の明示的なリダイレクトを参照してください2>&1
    • >&2現在割り当てられているのと同じオープンファイルへの割り当てを示します1。つまり、 またはy = xのようなfd[2] = fd[1]
  4. cmd arg arg arg同じプロセスで実行します。ファイルディスクリプタはデフォルト設定で変更され1ましたが、fd 1とfd 2の両方が次のようになりました。2同じファイルを開きます。

この例では、前の例のように/dev/nullを2回開かずに1回だけ開きます。 /dev/null は出力を削除するため、ここでの違いは重要ではありません。

では、いつ重要ですか?


万歳、あなたはもう終わった。みんな出力。しかし、時間が経つと、画面に表示される順序ですべての出力をファイルに入れたくなります。

私の以前の警告を無視し、信じられないほど簡単なものから始めてください。

cmd arg arg arg >file 2>file

これは前述のように機能しますが、内部を見るとfilestoutとstderrが奇妙にインターリーブされていることがわかります。おそらくstderrビットがファイルの先頭を上書きしているようです。くそー?

このフォームを使用すると、フォームをfile2回開くことができます。まあ、ええ...しかし、開いている各インスタンスfileには別々の出力位置があり、すべて0から始まります。したがって、stdoutが事前にメガバイトの出力を生成している間、stderrの出力位置はゼロのままで、時々エラーメッセージが生成されたときにのみ前方に移動します。


最後に、stderrとstdoutを単一のファイルとしてキャプチャする正しい方法です。

cmd arg arg arg >file 2>&1

これは、次の例とまったく同じ説明です。以前の誤った形式との重要な違いは、stdoutとstderrの両方が次を参照していることです。同じオープンインスタンスfileなど共有する出力位置。

答え3

簡単に言うと:

  • > /dev/null標準出力を/dev/null印刷せずにリダイレクトすることを意味します。
  • 2> &1stderrをstdoutにリダイレクトします(にリダイレクトされます/dev/null)。

しかし、何らかの理由でこれだけでは十分ではなく、まだ何かが印刷されます。

慣れていない場合に備えて、次の2つのいずれかに商品を送信できます。

  • ファイル記述子1は標準出力です。これは、アプリケーションがコンテンツを出力するときによく使用します。
  • ファイル記述子2はstderrです。これはあまり一般的ではありませんが、アプリケーションは通常エラーが発生するたびにstderrとして印刷します。

ほとんどのシェルでは、stdoutとstderrはデフォルトでシェルに印刷されます。を使用すると、> /dev/null標準出力が仮想シンクに渡されるため、シェルはもはや標準出力を印刷しません。ただし、stderrは影響を受けません。 「何らかの理由で」という言葉は、アプリケーションがstderrに書き込むということです。

関連情報