コンテンツにスキップ

スクリプト@ユーティリティ

はじめに

本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。


01. シェルスクリプト

シェルスクリプトとは

ユーティリティの処理を手続き的に実装したファイル。


シェバン

最初の『#!』をシェバンという。

#!/bin/bash

echo "foo"
echo "bar"
echo "baz"


ヒアドキュメント

▼ ヒアドキュメントとは

ヒアドキュメントで作成したシェルスクリプトには、各行にechoが追加される。

慣例として、終了文字列にはEOF/EOT/EODを使用するが、どんな文字でも良い。

#!/bin/bash

cat <<EOF > echo.sh
#!/bin/bash
foo
bar
EOF
#!/bin/bash

echo foo
echo bar

▼ ヒアドキュメント内の記号エスケープ

一部の記号 (例:{}) を文字として使用する場合、エスケープしないとヒアドキュメント内で使用できない。

終了文字列 (例:EOF) をシングルクオートで囲うと、エスケープできる。

#!/bin/bash

cat << 'EOF' > echo.sh
#!/bin/bash
${FOO}
${BAR}
EOF
#!/bin/bash

echo foo
echo bar

バックスラッシュを使用して、個別にエスケープすることもできる。

#!/bin/bash

cat <<EOF > echo.sh
#!/bin/bash
${FOO}
\${BAR}
EOF
#!/bin/bash

echo foo
echo ${BAR} # エスケープしたため、変数は展開しない

▼ ヒアドキュメント内への変数展開

終了文字列をシングルクオートで囲わずにエスケープしないことで、変数の記号 (例:{}) を使用できる。

#!/bin/bash

FOO=foo
BAR=bar

cat <<EOF > echo.sh
#!/bin/bash
${FOO}
${BAR}
EOF
#!/bin/bash

echo foo
echo bar


コメント

▼ 改行時にコメントを挿入

改行時にコメントを挿入すると、以降のオプションがコメントアウトされてしまう。

コメントをバッククオートで囲い、バックスラッシュで区切る必要がある。

#!/bin/bash

echo foo \
  `# コメント` \
  bar \
  `# コメント` \
  baz

反復

▼ for

*実装例*

#!/bin/bash

for i in 1 2 3 4 5; do
   echo "$i"
done


条件分岐

▼ switch-case

シェル変数に代入された値によって、処理を分ける。

全ての場合以外をアスタリスクで定義する。

*実装例*

#!/bin/bash

case "${ENV}" in
    "tes")
        VAR="foo"
    ;;
    "stg")
        VAR="bar"
    ;;
    "prd")
        VAR="baz"
    ;;
    *)
        echo "The parameter "${ENV}" is invalid."
        exit 1
    ;;
esac

▼ if

#!/bin/bash

if [ $VAR="" ]; then
  echo "空文字です";
else
  echo "空文字ではありません";
fi
#!/bin/bash

if [ -z "$VAR" ]; then
  echo "変数なし or 空文字です";
else
  echo "変数が設定されています";
fi
#!/bin/bash

if [ -n "$VAR" ]; then
  echo "NULLです";
else
  echo "NULLではありません";
fi

終了コードを条件とすることで、エラーが起こった場合の条件分岐を実装できる。

#!/bin/bash

if [ $? -ne 0 ]; then
  echo "エラーなので別の処理を実行します";
else
  echo "エラーではないため、正しい処理を実行します";
fi


実行方法

▼ source

現在の親プロセスのまま、シェルスクリプトを実行する。

そのため、シェルスクリプトの実行前に定義されたシェル変数を使用できる。

また、シェルスクリプト内で定義したシェル変数は、シェルスクリプトの実行後も維持される。

$ source hello.sh

▼ bash

現在の親プロセスから子プロセスを作成し、シェルスクリプトを実行する。

そのため、シェルスクリプトの実行前 (親プロセス) に定義されたシェル変数を使用できない。

また、シェルスクリプト内 (子プロセス) で定義したシェル変数は、シェルスクリプトの実行後に破棄される。

$ bash hello.sh

. (ドット)

$ . hello.sh

▼ パス指定

新しくインタラクティブを開き、処理を実行する。

そのため、シェル変数のライフサイクルはbashプロセスと同じである。

相対パスもしくは絶対パスでシェルスクリプトを指定する。

実行するファイルをカレントディレクトリ配下に配置できない。

$ ./hello.sh


02. Makefile

Makefileとは

ユーティリティの特にビルド (コンパイル + リンク) に関する処理を、シェルスクリプトではなくターゲットとして実装したファイル。

ただし、コンパイル以外を実装しても良い。


セットアップ

▼ apkリポジトリから

ほとんどのOSで、makeコマンドはプリインストールされているが、Alpine Linuxでは別途インストールが必要である。

$ apk add make


ロジック

▼ シェルの選択

シェルの種類を選択する。

種類ごとに使用できるオプションがやや異なる。

また同時に、setコマンドのオプションを有効化でき、これは全てのターゲットに適用される。

SHELL=/bin/bash -xeu

シェルによって使用できるオプションが少しだけ異なることに注意する。

# bashのpipefailオプションを使用する。
SHELL=/bin/bash -o pipefail

▼ ターゲット

ターゲットとして、単一/複数の名前を定義できる。

コマンドはタブで改行する必要がある。

foo:
    echo "foo"

bar:
    echo "bar"

baz qux: # 複数のターゲット名
    echo "baz"

▼ ターゲット間依存関係

特定のターゲットの実行前に、他のターゲットを実行しておきたい場合、依存関係を定義できる。

これは複数定義できる。

foo:
    echo "foo"

bar: foo # fooを事前に実行する。
    echo "bar"

baz: foo baz # foo、bazを事前に実行する。
    echo "baz"

.PHONY

ターゲットと同じ名前のファイルがある場合、makeコマンドでターゲットを指定できなくなる。

.PHONYを使用すると、ファイル名ではなくターゲットを明示できる。

# ターゲットであることを明示する。
.PHONY: foo bar baz qux

foo: # fooという名前のファイルがあると、実行できない。
    echo "foo"

bar:
    echo "bar"

baz qux:
    echo "baz"


変数

▼ 即時評価代入

変数の代入を定義したタイミングで変数の代入が行われる。

FOO:=foo

echo:
    echo "${FOO}" # echo

▼ 遅延評価代入

変数をコールしたタイミングで変数の代入が行われる。

FOO=foo

echo:
    echo "${FOO}" # echo foo

ターゲット内では、標準出力への出力をシェル変数に代入できない。

そのため、シェル変数はターゲット外で定義する必要がある。

また、遅延評価で代入し、$(shell ...)とする必要がある。

FOO=$(shell echo "foo")

echo:
    echo "${FOO}"


実行方法とオプション

▼ make

Makefileが配置された階層で、makeコマンドの引数としてターゲット名やシェル変数を渡せる。

Makefile内でシェル変数のデフォルト値を定義できる。

$ make <ターゲット名> <シェル変数名>=<値>

*実装例*

$ make foo FOO=foo
FOO=default

foo:
    echo "${FOO}"


Makefileのよくある使い方

一般的に、Makefileはパッケージのビルドとインストールのために実装される。

この時に慣例として、ターゲット名はmake (ターゲット無し) とinstallになっていることが多い。

(1)

パッケージをインストールする。

# パッケージを公式からインストールと解答
$ wget <パッケージのリンク>
$ tar <パッケージのディレクトリ名>


# ビルド用ディレクトリの作成。
$ mkdir build
$ cd build
(2)

ルールが定義されたMakefileをconfigureファイルを元に作成する。

# configureへのパスに注意。
$ ../configure --prefix="<コードのインストール先のパス>"
(3)

パッケージのコードからexeファイルをビルドする。

# -j で使用するコア数を宣言し、処理速度を上げられる。
$ make -j4
(4)

任意で、exeファイルを検証する。

$ make check
(5)

作成されたコードのファイルを、指定したディレクトリ配下にコピーする。

# installと命令するが、実際はコピー。
$ make install
(6)

元となったコードやバイナリ形式のコードを削除。

$ make clean