(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コマンドで関数を呼び出したのが原因。
これからスクリプトを作成するときには気をつけないとね。