HOGE=xxx && コマンドの挙動を調べる
遭遇したこと
以下のコマンドを実行するシェルを実行したら、uvicorn内で動くアプリケーションにHOGEという変数が渡らないということがあった。
HOGE=xxx && \
uvicorn main:app --port 8080
&& は 左のコマンドの終了ステータス(echo $?)が0のときに右のコマンドが実行されるやつ。
なので、HOGE=xxxとuvicornはそれぞれ別コマンド扱いだから、反映されていなかったのだろうか?と思い、
HOGE=xxx \
uvicorn main:app --port 8080
こうすればうまく動いた。めでたしめでたし。
ふと気になったこと
ここからはある意味蛇足。
HOGE=xxxという感じの変数とそれを実行するコマンドを && でつなげたら基本は、変数使えないよね?
と思って調べてたときに、以下のコマンドだとちゃんと変数の中身が見れた。
$ HOGE=xxx && echo $HOGE
xxx
HOGE=xxxとecho $HOGEは別プロセスになるだろうから、空文字が出力されるのを期待していた。
そもそも別プロセスなんだろうか?というのを見てみたときに、それも一緒だった。
$$でいまのプロセス番号を調べる。
$ echo $$ && echo $$
15253
15253
psしてみると、いま起動しているターミナルと同じプロセスだった。
$ ps | grep zsh
15253 pts/0 00:00:00 zsh
echoが組み込みコマンドなので、同じプロセス内で起動するということな気がする
$ which echo
echo: shell built-in command
なので実質、HOGE=xxx とターミナルで打ったあとに、echo $HOGEと打つのと同じ。
$ HOGE=xxx
$ echo $HOGE
xxx
ちょっと実験
以下のようなスクリプトecho_test.shを用意する
echo $$
それをコマンドラインで実行する
$ echo $$ && ./echo_test.sh
15253
99279
実質 echo $$ && echo $$ と変わらないわけなのだが、./echo_test.shは別プロセスとして起動している。
以下のようなスクリプトecho_test.shを用意する
echo $$
次にecho_test.shを修正する
echo $HOGE
ターミナルで実行すると、空文字が出力される。
ちなみに、上記を実行したあとに、echo $HOGEってターミナルで打つと、xxxが出力される。HOGE=xxxが反映されているのは、このターミナルで起動しているプロセスのみだということがわかる。
$ HOGE=xxx && ./echo_test.sh
# 何も出ない
# 続けざまにecho $HOGEすると、ちゃんと設定されている
$ echo $HOGE
xxx
冒頭でやったような、&&をつけずに、ひとつのコマンドとして実行すれば、ちゃんと設定したとおりに出力される。
なお当たり前ではあるのだが、同じターミナルで echo $HOGE すると、今度は何も出ない。
$ HOGE=xxx ./echo_test.sh
xxx
$ echo $HOGE
# 何も出ない
あとは、.bashrcや.zshrcでよくやる export を設定すれば && つきでいける。
exportは子プロセスにもその定義した変数を渡すことができるので。
$ export HOGE=xxx && ./echo_test.sh
xxx
$ echo $HOGE
xxx
exportのちょっと面白かった動き
実験中、面白い挙動するなと思ったのが、exportで定義した変数を書き換えるやつ。
echo_test.shを呼び出す別のスクリプトでvariable_test.shを用意する。
HOGE=aiueo && ./echo_test.sh
# echo_test.sh
# echo $HOGE
ターミナル上でHOGEを何もexportしていなければ、出力されない。
HOGE=aiueoとしているのも、variable_test.shのプロセス内のみであり、後続のecho_test.shに引き継がれないからだ。
$ ./variable_test.sh
# 何も表示されない
ただ、HOGEをexportすると変わる。
$ export HOGE=xxx && ./variable_test.sh
aiueo
てっきりexportしたHOGE=xxxが適用されて、xxxと出力されると思ったけど、variable_test.sh内でaiueoに書き換えられて、それがそのまま次のecho_test.shのプロセスへ引き継がれるらしい。
exportコマンドで、exportして子プロセスに引き継がれる変数を列挙できるので、それを使って確認をしてみる。
variable_test.shを以下に変更
# HOGE=aiueoしたあとに、HOGEがどう変わっているのか見てから、./echo_test.shを呼び出す
HOGE=aiueo && export | grep HOGE ; ./echo_test.sh
ターミナル上で実行してみる。
$ export HOGE=xxx && export | grep HOGE ; ./variable_test.sh
HOGE=xxx
HOGE=aiueo
aiueo
1行目がvariable_test.shを実行する前のexportしたHOGEの中身。
2行目がvariable_test.sh内でaiueoに変更したあとの、exportしたHOGEの中身。
一度exportされた変数は、ずっと子プロセスに引き継がれるし、途中で書き換えてしまうこともできるんだなとわかった。
おわりに
そもそも変数定義のあとに && をつける意味ってほぼ無い気はしている(そもそも変数定義で失敗する状況が思いつかない)。
Discussion