ひゃまだのblog

ひゃまだ(id:hymd3a)の趣味のブログ

Bashのパイプを利用した関数呼び出しの罠

(2024-05-01 初稿)

よく言われていることだが、Bashでパイプを使うと、サブシェルを使うと思わぬ弊害がでる記事はよく見ていたのだが、自分でスクリプトを作成してハマってみて、ようやく理解できた。

確認のサンプルスクリプト

関数の呼び出しの引数をつなげて、グローバル変数に保存し、エコー出力しながら、最後に変数全体を出力するスクリプト

#!/usr/bin/env bash
# sample script global variable with pipe redirect

G_Var=""

ex_func() {
  G_Var+=" $1"
  echo "$G_Var"
}

ex_func "Big"                    # ここを変更
ex_func "Dog"                    # ここを変更
echo "Last: "${G_Var}

上記スクリプトを実行すると、期待どおり、以下になる。

 Big
 Big Dog
Last:  Big Dog

しかし、上記スクリプトの「ここを変更」の部分を以下のようにパイプを使うように変更すると、以下のとおりおかしな結果になる。

ex_func "Big" | tee test.txt
ex_func "Dog" | tee -a test.txt
 Big
 Dog
Last: 

パイプを利用することで、呼び出した関数がサブシェルで実行されるため、呼び出し元の変数は変更されないのが理由らしい。

ちなみに、「ここを変更」の部分を、以下のとおりリダイレクトを利用すると、正常に動作する。

ex_func "Big" > test.txt
ex_func "Dog" >> test.txt
Last:  Big Dog

もともと動作していたスクリプトをついでにファイルにも保存しようとしてteeコマンドで関数を呼び出したのが原因。

これからスクリプトを作成するときには気をつけないとね。