Tech Racho エンジニアの「?」を「!」に。
  • 開発

[bash]サブシェルがパイプで受け取った標準入力の扱いとcdコマンドの動作

こんにちは、hachi8833です。

bashのサブシェルで標準入力を受け取った場合の扱いについて社内で行われたやりとりをメモします。

検証にはDocker上で動くUbuntu Linux(4.4.0-47-generic)を使いました。

質問

bashのサブシェルについての疑問です。以下のコマンドがあるとします。

$ echo "aiueo" | (cd /home/hoge && cat - )
  1. サブシェル(上の()で囲まれた部分)はパイプで受け取った標準入力をどう扱うか
  2. cdは標準入力をどう扱うか
  3. 実行してみると以下のようにcatまで標準入力が届いているように見えるが、cdは何が行われていたのか

question

回答

1. サブシェルはパイプで受け取った標準入力をどう扱うか

標準入力の扱いについては、サブシェルであってもなくても同じです。以下のように、パイプのつなぎ先がサブシェルであってもなくても出力は同じです。

ans 1

2. cdは標準入力をどう扱うか

cdコマンドに標準入力を渡すと何も行われず(ディレクトリも変わりません)、何も出力せずに終了します。

ans 2

  • 上: パイプで標準入力を渡すと、cdは何も出力しないので、echoも出力されません。
  • 下: セミコロンで区切った場合、echoの出力とcdはそれぞれ行われます。

注意: cdシェルコマンドなので、cdを実行してもプロセスは起動しません。

3. 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 -)

cat'n'cat

再回答

$ echo "a" | (cat - && cat -)
  • 1番目のcat -の段階で標準入力は空っぽになります。
    • もし1番目のcat -cdだったら、cdは標準入力の情報にまったく触らないので、そのまま残り続けます(標準入力を受け取りません)。
  • 2番目のcat -は、空っぽの標準入力を受け取るので何も出力しません。

参考までに、以下のようにすれば2番目のcatで出力されます。

$ echo "a" | (cat - | cat -)

以下の実行例では、2番目のcatが機能していることを確認するために間にsedをはさんでいます。

second cat

関連記事


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。