Linuxのstdin、stdout、およびstderrとは何ですか?

stdinstdoutstderrあなたは、Linuxのコマンドを起動したときに作成されたストリームの3件のデータがあります。それらを使用して、スクリプトがパイプされているのかリダイレクトされているのかを判断できます。その方法をお見せします。

ストリームが2つのポイントに加わる

すぐにLinuxと学び始めるとUnixライクなオペレーティングシステムでは、用語渡って来るstdinstdoutstederr。これらは、Linuxコマンドの実行時に確立される3つの標準ストリームです。コンピューティングでは、ストリームはデータを転送できるものです。これらのストリームの場合、そのデータはテキストです。

水流のようなデータ流には、2つの目的があります。それらにはソースと流出があります。使用しているLinuxコマンドは、各ストリームの一方の端を提供します。もう一方の端は、コマンドを起動したシェルによって決定されます。その端は、コマンドを起動したコマンドラインに従って、ターミナルウィンドウに接続されるか、パイプに接続されるか、ファイルまたは他のコマンドにリダイレクトされます。

Linux標準ストリーム

Linuxでは、 stdinは標準入力ストリームです。これは、入力としてテキストを受け入れます。コマンドからシェルへのテキスト出力は、stdout(標準出力)ストリームを介して配信されます。コマンドからのエラーメッセージは、stderr(標準エラー)ストリームを介して送信されます。

したがって、2つの出力ストリームstdoutstderr、および1つの入力ストリームがあることがわかりますstdin。エラーメッセージと通常の出力にはそれぞれ、それらをターミナルウィンドウに運ぶための独自のコンジットがあるため、互いに独立して処理できます。

ストリームはファイルのように処理されます

Linuxのストリームは、他のほとんどすべてと同様に、ファイルであるかのように扱われます。ファイルからテキストを読み取ったり、ファイルにテキストを書き込んだりできます。これらのアクションは両方とも、データのストリームを伴います。したがって、データのストリームをファイルとして処理するという概念は、それほど難しいものではありません。

プロセスに関連付けられた各ファイルには、プロセスを識別するための一意の番号が割り当てられます。これはファイル記述子として知られています。ファイルに対してアクションを実行する必要がある場合は常に、ファイル記述子を使用してファイルを識別します。

これらの値は、常にのために使用されているstdinstdout,stderr

  • 0:stdin
  • 1:標準出力
  • 2:stderr

パイプとリダイレクトへの反応

誰かが主題を簡単に紹介できるようにするための一般的な手法は、トピックの簡略版を教えることです。たとえば、文法では、ルールは「Cの後を除いてEの前にI」であると言われます。しかし実際には、この規則に従う場合よりも多くの例外があります。

同様の静脈では、およそ話をするときstdinstdoutおよびstderr プロセスが知っていることも、その3つの標準ストリームが終了される心配もないということが認められた公理を小走りすると便利です。プロセスは、その出力が端末に送られるのか、ファイルにリダイレクトされるのかを気にする必要がありますか?入力がキーボードからのものなのか、別のプロセスからパイプされているのかさえわかりますか?

実際、プロセスは、チェックすることを選択した場合、プロセスを認識します(または、少なくともそれを見つけることができます)。ソフトウェアの作成者がその機能を追加することを決定した場合、プロセスはそれに応じて動作を変更できます。

この振る舞いの変化は非常に簡単に見ることができます。次の2つのコマンドを試してください。

ls

ls | ネコ

lsコマンド振る舞いが異なっている場合、その出力は、( stdout)別のコマンドにパイプされています。これは ls、単一列の出力に切り替わるということであり、によって実行される変換ではありませんcat。またls、出力がリダイレクトされている場合も同じことを行います。

ls> capture.txt

猫capture.txt

stdoutとstderrのリダイレクト

専用ストリームによってエラーメッセージが配信されることには利点があります。これは、コマンドの出力(stdout)をファイルにリダイレクトしてもstderr、ターミナルウィンドウにエラーメッセージ()が表示されることを意味します。必要に応じて、エラーが発生したときに対応できます。また、stdoutリダイレクト先のファイルがエラーメッセージによって汚染されるのを防ぎます。

次のテキストをエディターに入力し、error.shというファイルに保存します。

#!/ bin / bash echo "存在しないファイルにアクセスしようとしています" cat bad-filename.txt

次のコマンドでスクリプトを実行可能にします。

chmod + x error.sh

スクリプトの最初の行は、stdoutストリームを介してテキストをターミナルウィンドウにエコーします 。2行目は、存在しないファイルにアクセスしようとします。これにより、を介して配信されるエラーメッセージが生成されstderrます。

次のコマンドでスクリプトを実行します。

./error.sh

我々は両方の出力のストリームことを見ることができ、stdoutかつstderr、ターミナルウィンドウに表示されています。

出力をファイルにリダイレクトしてみましょう。

./error.sh>capture.txt

経由で配信されるエラーメッセージstderrは、引き続きターミナルウィンドウに送信されます。ファイルの内容をチェックして、stdout 出力がファイルに送られたかどうかを確認できます。

猫capture.txt

からの出力stdinは、期待どおりにファイルにリダイレクトされました。

>リダイレクション記号はで動作しますstdoutデフォルトでは。数値ファイル記述子の1つを使用して、リダイレクトする標準出力ストリームを指定できます。

明示的にリダイレクトする  stdoutには、次のリダイレクト命令を使用します。

1>

明示的にリダイレクトする  stderrには、次のリダイレクト命令を使用します。

2>

もう一度テストしてみましょう。今回は以下を使用します2>

./error.sh 2> capture.txt

エラーメッセージはリダイレクトされ、stdoutechoメッセージはターミナルウィンドウに送信されます。

Capture.txtファイルの内容を見てみましょう。

猫capture.txt

stderr予想通りのメッセージがcapture.txtです。

stdoutとstderrの両方をリダイレクトする

確かに、どちらかstdoutまたはstderrファイルに互いに独立してリダイレクトできる場合は、両方を同時に2つの異なるファイルにリダイレクトできるはずですか?

はい、できます。このコマンドはstdout、capture.txtstderrというファイルとerror.txtというファイルに転送されます。

./error.sh 1> catch.txt 2> error.txt

出力のストリーム(標準出力と標準エラー)の両方がファイルにリダイレクトされるため、ターミナルウィンドウに表示される出力はありません。何も起こらなかったかのように、コマンドラインプロンプトに戻ります。

各ファイルの内容を確認してみましょう。

猫capture.txt
cat error.txt

stdoutとstderrを同じファイルにリダイレクトする

それは素晴らしいことです。標準出力ストリームのそれぞれが独自の専用ファイルに送られます。私たちができる他の唯一の組み合わせは、両方stdoutstderr同じファイルに送信することです。

これは、次のコマンドで実現できます。

./error.sh> fetch.txt 2>&1

それを分解しましょう。

  • ./error.sh:error.shスクリプトファイルを起動します。
  • > catch.txtstdoutストリームをcapture.txtファイルにリダイレクトします。>の省略形です1>
  • 2>&1:これは&>リダイレクト命令を使用します。この命令を使用すると、あるストリームを別のストリームと同じ宛先に到達させるようにシェルに指示できます。この場合、「ストリーム2を、stderrストリーム1と同じ宛先にリダイレクトする」と言っていますstdout

目に見える出力はありません。それは励みになります。

Capture.txtファイルをチェックして、その内容を確認しましょう。

猫capture.txt

stdoutstderrストリームの両方が単一の宛先ファイルにリダイレクトされています。

ストリームの出力をリダイレクトしてサイレントに破棄するには、出力をに転送し/dev/nullます。

スクリプト内のリダイレクトの検出

コマンドがストリームのいずれかがリダイレクトされているかどうかを検出し、それに応じてその動作を変更する方法を説明しました。独自のスクリプトでこれを実現できますか?はい、できます。そして、それは理解して採用するのが非常に簡単なテクニックです。

次のテキストをエディターに入力し、input.shとして保存します。

#!/ bin / bash if [-t 0]; 次に、キーボードからのエコーstdin、パイプまたはファイルfiからのエコーstdin

次のコマンドを使用して実行可能にします。

chmod + x input.sh

巧妙な部分は角括弧内のテストです。-t(0)真(端末)オプションが戻る場合は、ターミナルウィンドウでファイルディスクリプタの終了に関連したファイル。テストの引数としてファイル記述子0を使用しましたstdin。これは、を表し  ます。

stdinがターミナルウィンドウに接続されている場合、テストは真になります。stdinがファイルまたはパイプに接続されている場合、テストは失敗します。

便利なテキストファイルを使用して、スクリプトへの入力を生成できます。ここでは、dummy.txtという名前のファイルを使用しています。

./input.sh <dummy.txt

出力は、入力がキーボードからではなく、ファイルからのものであることをスクリプトが認識していることを示しています。必要に応じて、スクリプトの動作を変更できます。

それはファイルリダイレクトでした。パイプで試してみましょう。

猫dummy.txt | ./input.sh

スクリプトは、入力がパイプされていることを認識します。より正確にstdinは、ストリームがターミナルウィンドウに接続されていないことをもう一度認識します。

パイプもリダイレクトも使用せずにスクリプトを実行してみましょう。

./input.sh

stdinストリームは、ターミナルウィンドウに接続され、スクリプトがそれに応じて、これを報告しています。

出力ストリームで同じことを確認するには、新しいスクリプトが必要です。次のようにエディターに入力し、output.shとして保存します。

#!/ bin / bash if [-t 1]; 次に、echo stdoutがターミナルウィンドウに移動します。それ以外の場合、echostdoutはリダイレクトまたはパイプされます。

次のコマンドを使用して実行可能にします。

chmod + x input.sh

このスクリプトに対する唯一の重要な変更は、角括弧内のテストです。のファイル記述子を表すために数字1を使用していますstdout

試してみましょう。出力をcat。にパイプします。

./output | ネコ

スクリプトは、その出力がターミナルウィンドウに直接送信されないことを認識します。

出力をファイルにリダイレクトすることで、スクリプトをテストすることもできます。

./output.sh>capture.txt

ターミナルウィンドウへの出力はありません。コマンドプロンプトに静かに戻ります。予想通り。

Capture.txtファイルの内部を調べて、何がキャプチャされたかを確認できます。これを行うには、次のコマンドを使用します。

猫capture.sh

この場合も、スクリプトの簡単なテストで、stdoutストリームがターミナルウィンドウに直接送信されていないことが検出されます。

パイプやリダイレクトなしでスクリプトを実行stdoutすると、ターミナルウィンドウに直接配信されていることが検出されます。

./output.sh

そしてそれはまさに私たちが見ているものです。

意識の流れ

スクリプトがターミナルウィンドウまたはパイプに接続されているか、リダイレクトされているかを判断する方法を知っていると、それに応じてスクリプトの動作を調整できます。

ロギングと診断出力は、画面に表示されるかファイルに表示されるかに応じて、多かれ少なかれ詳細になります。エラーメッセージは、通常のプログラム出力とは異なるファイルに記録できます。

通常の場合と同様に、知識が増えると選択肢も増えます。