- 開発
READ MORE
こんにちは、hachi8833です。
bashのサブシェルで標準入力を受け取った場合の扱いについて社内で行われたやりとりをメモします。
検証にはDocker上で動くUbuntu Linux(4.4.0-47-generic)を使いました。
bashのサブシェルについての疑問です。以下のコマンドがあるとします。
$ echo "aiueo" | (cd /home/hoge && cat - )
(
と)
で囲まれた部分)はパイプで受け取った標準入力をどう扱うかcd
は標準入力をどう扱うかcat
まで標準入力が届いているように見えるが、cd
は何が行われていたのか標準入力の扱いについては、サブシェルであってもなくても同じです。以下のように、パイプのつなぎ先がサブシェルであってもなくても出力は同じです。
cd
は標準入力をどう扱うかcd
コマンドに標準入力を渡すと何も行われず(ディレクトリも変わりません)、何も出力せずに終了します。
cd
は何も出力しないので、echo
も出力されません。echo
の出力とcd
はそれぞれ行われます。注意: cd
はシェルコマンドなので、cd
を実行してもプロセスは起動しません。
cat
まで標準入力が届いているように見えるが、cd
は何が行われていたのかサブシェル内でcd
すると、サブシェル内のカレントディレクトリが変更されます。
サブシェル内でカレントディレクトリを変更すると、サブシェルが別シェルとして起動します。たとえば、cd /home
だとカレントディレクトリは変更されますが、(cd /home)
ならカレントディレクトリは変更されません。
サブシェルを利用すると、メインのシェルのカレントディレクトリや環境変数に影響せずにcd
や環境変数設定を行えます。
サブシェルのサンプルスクリプトです。
$ echo "aiueo" | ( cd /tmp && cat - > aiueo.txt)
上のスクリプトはサブシェルで/tmpにaiueo.txtを作成し、実行後は元のディレクトリに戻ります。
なるほど、サブシェルはあんまり関係ないんですね。cd
が標準入力を受け取っても何もしないだろうというところまでは理解していました。
腑に落ちなかったのは、「それならcat
には何も届かないはずではないか?」という点です。たとえば以下を実行すると”a”は一度しか表示されません。質問3.はそこについてお聞きしたかったのでした。
$ echo "a" | (cat - && cat -)
$ echo "a" | (cat - && cat -)
cat -
の段階で標準入力は空っぽになります。
cat -
がcd
だったら、cd
は標準入力の情報にまったく触らないので、そのまま残り続けます(標準入力を受け取りません)。cat -
は、空っぽの標準入力を受け取るので何も出力しません。参考までに、以下のようにすれば2番目のcat
で出力されます。
$ echo "a" | (cat - | cat -)
以下の実行例では、2番目のcat
が機能していることを確認するために間にsed
をはさんでいます。