「BashでFizzBuzz」からShellScriptの基本的な書き方を思い出してみる


はじめに

あるとき自分のFacebookにこんな記事が出てきたんですよ。

ああ、8年……そんな経ったのですね……ちょうど特許検索エンジンのUI側をjQueryを鬼駆使ししてSPAなどという言葉もなかった頃にSPAみたいなことをやっていた時期だったと思います。

んで、その頃に当時の現場のCTO(頭脳も物理的にもつよつよなエンジニア)から腕試し的に書いてみろって言われたんですよ。
これくらい書けなきゃMac使わせない的なこと言われたんだったかな……?

FizzBussとは3の倍数のときに「Fizz」、5の倍数のときに「Buzz」と出力させる、コードの基礎が全て詰まっていると言われているよくある練習課題です。
3の倍数のときにアホになる例のネタと同じようなやつです。
Hello World の次ぐらいにやるやつですね。

えーと、コードは……

for ((i=1; i < 101; ++i));do if ((i%3==0 && i%5==0));then echo fizzbuzz;elif ((i%3==0)) ;then echo fizz;elif ((i%5==0));then echo buzz;else echo $i;fi; done

ワンライナーなのでよくわかりませんね。

Beautifyしてみた

整形するとこんな感じです。

for ((i = 1; i < 101; ++i)); do
    if ((i % 3 == 0 && i % 5 == 0)); then
        echo fizzbuzz
    elif ((i % 3 == 0)); then
        echo fizz
    elif ((i % 5 == 0)); then
        echo buzz
    else
        echo $i
    fi
done

なんか、「今だったらこんな書き方しないな?」な箇所がいくつかはあるんですが、どうして今そうしないのかよくわからないので、細かく紐解いてみましょう。

For文のループ

for ((i = 1; i < 101; ++i)); do
    # なんか処理
done

初期化式に再初期化式を実行して継続条件式が false になったら止めるっていう基本のループです。
do から done までの間の処理を継続条件式が true である限り繰り返し実行します。
今日日、式を3つ並べるforループなんてなかなか書かないですよね。
この書き方の場合、カッコは2つ使う必要があるようです。

for i in {1..100}; do
    # なんか処理
done

多分この形のいわゆる for-in 型のほうが使い勝手がいいのかなと思います。

if文の条件分岐

    if ((i % 3 == 0 && i % 5 == 0)); then
        echo fizzbuzz
    elif ((i % 3 == 0)); then
        echo fizz
    elif ((i % 5 == 0)); then
        echo buzz
    else
        echo $i
    fi

条件分岐ですね。 if で始まって、 elif とか else で分岐して、 fi で終わります。
でもShellScriptの条件文ってこんな感じに書くんじゃなかったっけ?って思ってたですよ。

if [ i -eq 5 ]; then
    # なんか処理
fi

この、ブラケット [] で囲まれた部分って、 test というコマンドのシンタックスシュガーなんですよね。
んで、このFizzBuzzではブラケットの代わりに二重括弧を使ってます。
実は二重括弧で囲まれた部分は let コマンドのシンタックスシュガーなんだそうで、数値の比較で絶大な威力を発揮します。(その代わり文字列比較ができません)

変数

変数への代入は普通に

i = 5

みたいな感じでできます。
参照のときは

echo $i

みたいな感じで、ドルマークを付けます。
letコマンドで参照するときはいらないようです。

参考ページ