地方エンジニアの学習日記

興味ある技術の雑なメモだったりを書いてくブログ。たまに日記とガジェット紹介。

【Bash】パイプ有無での実行シェルの違い

シェルスクリプトを書いていて関数を定義した際にlocalを付けずに変数を宣言するとグローバル領域に定義されたような動作をする。これはこれでグローバルにフラグを持っておいて関数内で書き換えたりっていう処理を書くなら直感的で個人的には良いなと思って理解していた。

#!/usr/bin/env bash

A=0

function f() {
  A=20
}

echo $A # = 0
f
echo $A # = 20

関数呼び出し後は変数Aには20が代入されグローバル変数が書き換えられている。ここで関数呼び出しの行でパイプを使って結果を取得したいケースで困ることがある。

#!/usr/bin/env bash

A=0

function f() {
  echo "Hello world"
  A=20
}

echo $A # = 0
f | grep "Hello"
echo $A # 20

関数呼び出しを行う際にパイプを付けると実行自体はサブシェルでの処理となって呼び出し元の変数は書き換えられない動作となってしまう。(PID自体はmainと同じPIDだがpipeを使用して呼び出した場合はサブシェル内で外部への影響が起きないと言うメリットがある)

参考
Each command in a pipeline is executed as a separate process (i.e., in a subshell).

bashのmanにもそのこと自体は書いてあった。pipe付けるとそれぞれ実行はサブシェルで行われるぞといった感じ。

bash(1): GNU Bourne-Again SHell - Linux man page

その他

Bashの変数スコープについてのメモ - Qiita