これまで
シェルもどき「oreshell」を自作している。
前回はリダイレクションの実装をした。
今回はパイプの実装、動作確認。
Unix系オペレーティングシステムのパイプ(pipe)、もしくはパイプライン (pipeline) とは、複数のプログラムの入出力をつなぐための仕組み(プロセス間通信)の一つである。独立した複数のプログラムを組み合わせる事で、多様かつ複雑なデータ処理を効率よく柔軟に実行できる利点がある。また、現有のソフトウエア資産の再利用が可能になるため、プログラム生産性の面でも利点もある。
wikipedia
上記のパイプライン例のイメージ図は以下の通り。
上記のパイプライン例では以下の処理を行っている。
上記の「ls」「grep ab」「sort」プロセスはすべて並列で実行し、各プロセスは「入力されたデータを処理して出力する」を逐次行う。
「ls」の実行が終わってから「grep ab」を起動するわけではない。「ls」が少し実行して少し出力するとそれを「grep ab」がパイプ経由で受け取って処理して出力する。
「カレントディレクトリにあるファイル名の一覧をある条件で取得したい」と思ったときに、それ専用のプログラムを書かなくても、上記パイプラインコマンドを実行するだけで取得することができる。
Unix系OSの場合はpipeシステムコールが用意されているのでそれを使って実現するのが一般的らしい。(Linuxのpipeシステムコール)
pipeシステムコールを呼ぶと、「パイプに書き込むための口」と「パイプから読み出すための口」のファイルディスクリプタを取得できる。
goではos.Pipe()があるのでoreshellではこれを使って実現する。
以前にリダイレクションの構文を書いたのでそれを拡張する。
oreshellのパイプの構文は以下の通り。
railroad diagram
「simple_command」を含めて全部くっつけるとこんな感じ。
以前に抽象構文木を書いたのでそれを拡張する。
パイプライン対応による変更点のみ説明。
解析対象の字句として「|」を追加する(説明は省略)。
構文に従って字句解析トークン群から抽象構文木を作成する(説明は省略)。
変更点の内、重要な箇所をピックアップして以下に説明。
上記の構造体を図に表すと以下の通り。
「★」がついている要素はパイプライン対応で使う要素である。
これらについてはあとで説明する。
抽象構文木(ast.PipelineSequence)から
process.Process#PipeWithNext()でプロセスと次のプロセスとの間にパイプを作成し、
を行う。
また、プロセスと次のプロセスの前後関係を設定する。
oreshellでパイプを実現できた。