bashからfishへ乗り換えました 第1回

Goro Yanagi
Aug 23, 2017 · 5 min read

bash scriptでよくはまる罠を、くどく調べてみます。

この度、長年使い続けていたbashからfishへ乗り換えました。すでに1年使い続けているので、おそらくもうbashに戻ることは無いでしょう。その理由を、bash、fish両方の側面からお話していきたいと思います。

今回はその第1回目。

bashでshell scriptを書き始めた時に誰もがはまる罠

手に馴染むshellは、command line interfaceとして利用するだけでは無く、shell scriptとして利用すれば、日々の業務の効率化に大いに役たちます。

さて、以下のshell script。

実用性は皆無ですが、seqコマンドとpipe(|)を組み合わせて、loop回数をエレガントに(?)制御している気になっています。

行してみると標準出力には、おそらく期待するであろう10では無く、0が出力されます。

$ ./pipe-while.sh
0

これは、ちょっとbashに慣れた人がはまる代表的な罠です。

コードを変更して、振る舞いを観測してみましょう。

loopの前後と内側に

ps --forest

を挿入してみました。それでは実行してみます。

$ ./pipe-while-2.sh
*** before loop ***
PID TTY TIME CMD
9525 pts/8 00:00:00 bash
10361 pts/8 00:00:00 \_ pipe-while-2.sh
10362 pts/8 00:00:00 \_ ps
*** inside loop ***
PID TTY TIME CMD
9525 pts/8 00:00:00 bash
10361 pts/8 00:00:00 \_ pipe-while-2.sh
10364 pts/8 00:00:00 \_ pipe-while-2.sh
10365 pts/8 00:00:00 \_ ps
*** after loop ***
PID TTY TIME CMD
9525 pts/8 00:00:00 bash
10361 pts/8 00:00:00 \_ pipe-while-2.sh
10366 pts/8 00:00:00 \_ ps

loopの内側だけpipe-while-2.shから同名の子プロセスが実行され、2つ目のpipe-while-2.shの子プロセスとしてpsコマンドが実行されています。

これからわかることは、

ループの外側と内側が別のプロセス

これが、この罠の本質です。

別のプロセスなので、loopの内側で変数の値を変更しても、loopの後に引き継げません。

(loopの外からloopの内側へは、引き継げています。これは子プロセスを生成するときに利用しているシステムコールfork()の仕様です)

この問題をさらに面倒くさくしているのが、

while loopを使えば、もしくはpipeを使えば、必ず同じ事がおきるわけでは無い

いくつかサンプルを見てみましょう。

$ ./pipe-only.sh
PID TTY TIME CMD
9525 pts/8 00:00:00 bash
10664 pts/8 00:00:00 \_ pipe-only.sh
10665 pts/8 00:00:00 \_ ps
10666 pts/8 00:00:00 \_ ps

pipeの前後のpsコマンドが、同じpipe-only.shの子プロセスとして発生しています。

(実行時の状況によりpsプロセスが1つしか表示されない場合があります)

次は pipe を使わずにwhile loopを使ってみます。

$ ./while-only.sh
*** before loop ***
PID TTY TIME CMD
9525 pts/8 00:00:00 bash
10733 pts/8 00:00:00 \_ while-only.sh
10734 pts/8 00:00:00 \_ ps
*** inside loop ***
PID TTY TIME CMD
9525 pts/8 00:00:00 bash
10733 pts/8 00:00:00 \_ while-only.sh
10735 pts/8 00:00:00 \_ ps
*** after loop ***
PID TTY TIME CMD
9525 pts/8 00:00:00 bash
10733 pts/8 00:00:00 \_ while-only.sh
10737 pts/8 00:00:00 \_ ps

loopの前後、内側のpsコマンドがすべて、while-only.shの子プロセスとして実行されています。

つまり、

pipe と while の合わせ技の時だけ気をつけろ

これは、熟練のプログラマも、しばらくbashから離れていると、うっかりやってしまいます。

今回はfishの話まで出来ませんでした(!!??)が、次回は同じ内容についてfishの視点から何か書いてみたいと思います。

それでは皆様よいshell生活を!

VELTRA Engineering

Posts from the VELTRA Engineering team. www.veltra.com

)

Thanks to Takuo Oki

Goro Yanagi

Written by

VELTRA Engineering

Posts from the VELTRA Engineering team. www.veltra.com

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade