shellscript の旅路

ああ、shellscript がうまくなりたい


Posted on Sat, Jun 23, 2018
Tags bash, shellscript

shellscript 上達への道

shellscript は最高だ。なぜなら、すべての OS に入っている。基本的な文法はあまり変わらず、コピペで渡せばどこでも動かせる…

そう思い始めたのは、ここ最近、仕事で使うようになってからの話で、IDE からプログラミングの世界に入った自分には、当初 shellscript は難しすぎた。

#!/bin/bash
a = "hoge" # line 2: a: command not found
echo $a

そう、これで動かないのが shellscript なのである。java, python から勉強した自分には当時、何がおきているのかわからなかった。 正しくは

#!/bin/bash
a="hoge"
echo $a # hoge

良かれと思った空白が、 shellscript では思わぬエラーになる。それが shellscript の世界なのである。

上達への道 1 : shellcheck をインストールする。いますぐに

brew install shellcheck

この記事を読むより先に mac なら上のコマンドで shellcheck をインストールしよう。linux, windows でもインストールできる。

shellcheck との出会いで shellscript の旅路は大きく変わった。最初の例も shellcheck を通すと

$ shellcheck hoge.sh

In a.sh line 2:
a = "hoge"
  ^-- SC1068: Dont put spaces around the = in assignments.

とエラーを出してくれる。エディタに shellcheck のプラグインをインストールすれば、shellscript を書いている最中に間違いに気づけるはずだ。

参考

上達への道 2 : set -eux を書こう

#!/bin/bash
set -eux

スクリプトを書く場合は、上記で始めよう。-e がコマンドが失敗したら(0以外で終わったら) 続行させない、-u は未定義の変数を参照させない、-x は実行するコマンドを一つ一つ出力する(デバッグ向け)

#!/bin/bash
set -eux

# パスワードなどターミナル出力してほしくない箇所は +x で除いておく
set +x
export $YOUR_PASS="password"
set -x

参考

上達への道 3 : 制御構造を覚えよう

最小限の制御構造は使えたほうが楽だ。代表的なのは for, if だろう

if

if 文では [ を使う。実はこれはコマンドなのである。

#!/bin/bash
set -eux

if [ -e "$HOME/Desktop" ]; then
  echo "Desktop exists"
fi

# これに等しい
if test -e "$HOME/Desktop"; then
  echo "Desktop exists"
fi

だから、if(exists(…)) を真似して、 if[-e ]; then のようなことができない。コマンドを空白で分けてやる必要があるのだ。 (次は空白が必要なのか…と思われた、あなた。そう、それが shellscript なのである)

また、&& で AND 条件などを行いたい場合は、 [[ を使うことがある。

Bashにおける括弧類の意味 - Qiita

for

DRY 原則にのっとる → Bashでいろいろループする - Qiita

ただ、よく業務で行うのが、ファイルや環境値(サーバ名など)を扱う場合だ。

#!/bin/bash
set -eux

for item in ("file1" "file2" "file3") ; do
    some_command $item
done

こういったちょっとしたスクリプトを書くことにより、社内で shell おじさんの栄えある称号をもらえたりする。

上達への道 4 : いろんなコマンドを覚えよう

「shell で上達したいなら、いろんなコマンドを覚えよう」

これが最も僕が伝えたいことだ。

例えば、文字列を置換したいとする。プログラミング言語を扱っていたら、まず言語のレファレンスで string パッケージの replace メソッドを探すだろう。

しかし、shellscript ではそうではない。端末にインストールされているコマンドを組み合わせて、高度な機能を実現する。

#!/bin/bash
set -eux

# コメント行の削除
cat source.txt | sed '/^#$/d'

では、文字列の置換は上記のコマンドで実現しないといけないのか? そんなことはないのである。

場合によっては、awk, GNU 版の gawk, あるいはその他のコマンドで置換してもよい。しかも、各コマンドには多種多様なオプションが用意されており、その中で最適なものを選ぶ必要がある。

OS にデフォルトで含まれていないコマンドを利用することももちろんある。例えば、json 文字列を扱うなら、多くの人は jq コマンドを利用するだろう。

shellscript の旅路は、インストールされているコマンドとの旅路と言って良い

参考

まとめ

shellscript はその癖がわかってくると、意外とあっさり書き始めることができる。

細かい作業の繰り返し、ちょっとしたサーバでの作業を shell におこして、この長い旅路を続けよう。