たとえば、bash は /bin/bash の下にあります。これは、bash がコマンドであり、各コマンドに標準入力、標準出力、標準エラーの 3 つの (0、1、2) ポアがあることを意味します。
これはシェルにも 100% 当てはまりますか、それともコマンドまたはプロセスとしてのシェルの特別な意味とは何か違うのでしょうか?
答え1
これは他のプログラムと同じです。これにより、他のプログラムと同様に I/O をリダイレクトおよびパイプすることができます。
echo "cat filename" | bash
パイプから標準入力を読み取るcat filename
と、コマンドが実行されます。bash
bash -c "echo foo" > filename
コマンドが実行されecho foo
、出力がファイルにリダイレクトされます。
Unix では、シェルに「特別な」点は何もありません。他のプログラムを実行することを主な目的とする、単なる普通のプログラムです。
答え2
いくつかの用語を区別してみましょう。
あ指示シェルに入力する内容です。エイリアスまたはシェル関数、またはそれは実行可能ファイル。
アン実行可能ファイルかもしれないバイナリ実行可能ファイル(つまり、マシンコードを直接含むもの)または脚本スクリプトには、bash スクリプト、sh スクリプト、perl スクリプト、awk スクリプト、sed スクリプト、python スクリプトなどが含まれます。
スクリプトの最初の2バイト(実行ファイルとして直接実行される場合)は#!
、改行が読み込まれるまでカーネルにさらにバイトを読み込むように指示する「マジックナンバー」で、それらのバイトをパスとして解釈します。バイナリ実行可能ファイル(空白で区切られた単一の引数(例#!/bin/awk -f
))を実行し、それバイナリ実行可能ファイル。スクリプト自体へのパスが引数として渡されます。
結局のところ、カーネルが実際に実行できるのはマシンコード、つまりバイナリ実行ファイルだけです。sh、bash、perl、python、awkなどのバイナリ実行ファイルは、通訳者。 スクリプトを解釈し、その命令を実行します。ただし、実行されるには、それ自体がマシン コード内に存在している必要があります。
プログラム(バイナリ実行ファイル)がカーネルによって実際に実行されると、それはプロセス。 バイナリ実行ファイルは、命令を含むファイルです。プロセス「プログラムの実行インスタンス」です。より具体的には、カーネルに組み込まれた抽象化であり、メモリ、環境変数、プロセスID(PID)が関連付けられています。ファイル記述子入力や出力、その他の属性に使用できる。実行ファイルは「同時に」複数回実行できる(シングルコアマシンで文字通り同時に実行できるわけではないが、カーネルがCPUサイクルを割り当てる方法により、思われるすべて同じプログラムのインスタンスであっても、実行中の各インスタンスは異なるプロセスになります。
0、1、2(標準入力、標準出力、標準エラー)はファイル記述子。 実のところ、これらが存在するのは慣例によるだけです。C を使用して、これらのファイル記述子をまったく与えずに他のプログラムを起動 (実行) (さまざまなバイナリ実行可能ファイルを実行) するプログラムを作成できます。 しかし、標準プログラムはすべてファイル記述子 0、1、2 が使用可能であることを前提として記述されているため、ほとんどの場合、エラーしか発生せず、プログラムは正しく動作しません。
これを完全に理解するには、プロセスがどのように生まれるか。 これは誕生の奇跡に少し似ています。;) すべてのプロセスは、別のプロセス。システムを起動したときに最初のプロセスがどのように開始されるかを気にする必要はありません。PID 1 のプロセスは「init」と呼ばれ、オペレーティング システムが機能するために必要な他の基本プロセスを開始します。
プロセスが別のプロセスを開始する方法は、次の 2 つの基本的な手順で行われます。フォークそして実行します。 これらは両方ともシステムコールであり、プロセスが送信するアクション/リクエストです。カーネルにカーネルだけが実際に実現できます。
「フォーク」とは、(簡単に言えば)「カーネル、私のコピーを作ってください」という意味です(「私」とは実行中のプロセスです)。カーネルは、プロセスの完全なコピーを作成します。つまり、ファイル記述子、メモリ、実行状態(インスタンスであるプログラムを構成する命令に従っている状態)、環境変数などです。つまり、プロセスの「クローン」です。では、オリジナルとコピーを区別するにはどうすればよいでしょうか。それは、システムfork
コールの戻りステータスだけです。子プロセスは「0」(成功)を取得し、親プロセスは新しく作成された子プロセスの PID を取得します。したがって、この戻りステータスを調べることで、各プロセスは次に何をすべきかを把握できます(同じ一連の命令に従っていることを思い出してください)。
「Exec」は実際には「execve()」です。簡単に言うと、カーネルに「カーネル、交換する「私はプロセスです」と「______ファイルで指定されたプログラムのインスタンス」をプログラマーは指定します。議論新しいプロセスが持つもの、そして環境(環境変数の配列) を持つことになります。
シェルにコマンドを入力すると、実際には(ほとんどの場合、シェル組み込みコマンドなどの特殊なケースは無視してcd
)シェル(実行中のプロセス)が実行されます。フォーク、その後幹部指定したコマンド。
のように出力または入力のリダイレクトを行った場合/bin/echo hello > /dev/null
、分岐した子プロセスはexec
ingエコーの前に/dev/null
それに応じてファイル記述子が調整され、ファイル記述子 1 (この例では)が端末または以前の場所ではなく、そこに結び付けられます。
したがって、実行可能ファイルの実行中のインスタンスは、/bin/bash
入力を読み取ることができるファイル記述子 0、出力を書き込むことができるファイル記述子 1、およびエラー メッセージや同様の入出力を読み書きできるファイル記述子 2 が利用可能であると想定されます。