はじめに
初学者の私は、ターミナルの環境とファイルの実行について学んだ時の解釈をまとめました。
何となく黒い画面で文字を打てば、出力が返ってくるという程度の認識を持っていましたが、
皆さんが初学者の時はいかがだったのでしょうか。
echo "hello world" | python main.py
単純なこのコマンドによってどんな処理が起こっているのかを、私なりに解釈して見ました。
パイプは標準ストリームを渡すパイプである
コマンドラインから、パイプを用いてファイルへ渡す場合以下のようになります。
# パイプから、main.pyへstdinを渡す
echo "hello world" | python main.py
このような時"hello world"がmain.pyへ渡されます。
具体的にいうと**echo "hello world"**のstdoutをパイプが受取り、ファイルのstdinとして入力されます。
標準ストリーム
- stdin(標準入力): プロセスが持つ入力の入口
- stdout(標準出力): プロセスが持つ出力の出口
- stderr(標準エラー): プロセスが持つエラーの出口
標準ストリームは、プロセスが持つ入出力用の「接続口」です。
この口を使うかどうかはプロセスの設計次第であり、
たとえば echo は stdin をほとんど利用せず、stdout のみを使います。
標準ストリームと引数のどちらで使うかは役割次第
あくまで標準ストリームはプロセスの口が提供されている状態である。
echo "hello world"
# これはstdinを使っていないがstdoutは使う
| python3 main.py
# これはパイプがstdin->stdoutをする。main.pyも受取れるが使うかは設計次第。
つまり入出力は決まった口から入ってくるが使うかどうかはプロセスに委ねられている。
他にもプロセスの口は存在する。
- コマンドライン引数(argv)
- ファイル(file)
- 環境変数(env)
- 明示的にファイルを開く(open())
- パイプ(pipe)
- シグナル(signal)
プロセスの口が持つ役割は、それぞれの得意な口で分担される
全てを満足する機能は存在しないように、得意と不得意を持った口を使うことが最適解であると思います。
使われる目的によって様々な軸が存在あります。
- 時間: プロセス実行前か実行中か
- データ量: 少量か大量か
- 明示性: 明示的か暗黙的か
- 同期性: 同期的処理か非同期処理か
- 再利用性: 一度きりの入力か、永続的な入力か
入力源とするために、どのような状態で実装しておくかが判断基準と思っています。
入力の終端がこない??
Pythonでこのようなコードを書いてシェルで実行すると、以下のようなことが起こります。
print(sys.stdin.read()) # stdinを読み込む
python3 main.py
入力を永続的に待つような状態になりました。
どうも、read()は入力が終わったということを認識しない限り、終わっていないと判断して待ち続ける仕様みたいです。
使う側からしたら、入力してないから終わらないという至極当たり前の挙動ですね。
これを”入力の終端(EOF)"といいます。
出力するプロセスがない場合には、入力の終端を明示的に渡してあげなければ来ないということは、
逆に入力を行なってEOFを明示してあげるということで、データを自由な内容で渡すことも可能ではありますが、
制御や処理の自動化を行うに当たり、処理内容がブレることはあまり良くないためユースケースは限られてくるのだろうなと解釈しました。(不備あれば教えてください。)
1回目のEOFの明示によって、入力の終端を読み取って、Pythonファイルを実行しています。
まとめ
今回の学習で学べた教訓として、
- 入力→処理→出力という形式にも複数の経路を持っている
- 設計思想によって何を使うかの最適なものを選定する
ということが学べました。
エンジニアリングを学ぶというものは、知識の幅が広すぎて理解と活用に非常に時間を要すると感じます。
しかし、少しずつ知識の幅と深さを広げていくことが学習の本質だと私は考えています。
これからも、成長していけるように精進していきたいと思います。
皆さんの、この学習法やこんなマインドが初学者の際に役に立ち、効率的であったということがあればぜひ教えてください。
様々なコメントお待ちしています。

