Makefileでシェルスクリプトを便利にする.ONESHELL
はじめに
Makefileは、主にビルドプロセスの管理に使用されるツールですが、シェルスクリプトを組み込むことで、タスクの自動化や簡単なスクリプト実行もできます。しかし、Makefile内で複数行のシェルコマンドを書く場合、シェルの挙動やMakefileの構文に関するいくつかの気をつけるポイントがあります。そんな中、.ONESHELL
を使うことで、シェルスクリプトをよりシンプルで効率的に書くことができます。
.ONESHELL
とは
.ONESHELL
は、Makefile内で複数行のシェルコマンドを1プロセスで実行するためのオプションです。通常、Makefileでは各コマンドは個別のプロセスで実行されますが、.ONESHELL
を使うと、複数のコマンドが1つのシェルセッション内で実行されるようになります。これにより、シェルの環境を共有でき、例えば変数の値を保持したまま次のコマンドに渡すことが可能になります。
.ONESHELL
の基本的な使い方
.ONESHELL
はMakefileの一番上に書くことで、Makefile内のすべてのターゲットに対して適用されます。
.ONESHELL:
以下のように書くと、指定したターゲットだけで、.ONESHELL
を使うことができます。
.ONESHELL: target
SAMPLE1: シンプルな使い方
次に、シンプルな例を見てみましょう。.ONESHELL
を使わない場合と使った場合の違いを理解するために、以下の2つのMakefileを比較します。
.ONESHELL
を使わない場合
target:
echo "Step 1"
VAR=10
echo "Step 2: $${VAR}"
このMakefileは、echo
コマンドを2回実行していますが、変数VAR
は最初のecho
コマンドの後に設定され、2番目のecho
コマンドでは変数の値が表示されません。なぜなら、Makefileではデフォルトで各コマンドが個別のシェルセッションで実行されるためです。
.ONESHELL
を使った場合
.ONESHELL:
target:
echo "Step 1"
VAR=10
echo "Step 2: $${VAR}"
.ONESHELL
を使うと、すべてのコマンドが1つのシェルセッション内で実行されるため、VAR=10
で設定した変数を次のコマンドで利用できるようになります。この場合、echo "Step 2: $${VAR}"
は正しくStep 2: 10
と変数の値を表示します。
SAMPLE2: 複数行のシェルスクリプトを簡潔に
次に、少し複雑なシェルスクリプトをMakefile内で記述する例を見てみましょう。
.ONESHELL
を使わない場合
SHELL := /bin/bash
target:
@echo "start"
@source .env
@./test.sh "$${TEST_VAL1}"
@echo "end"
このMakefileでは、source
とtest.sh
とecho
のコマンドが個別に実行されます。.envに定義された環境変数のTEST_VAL1をtest.shに渡すことはできません。
ちなみに、test.sh
がエラーになると、最後のecho
コマンドは実行されません。
$ make target
start
arg1=
end
.ONESHELL
を使った場合
.ONESHELL:
SHELL := /bin/bash
target:
@echo "start"
source .env
./test.sh "$${TEST_VAL1}"
echo "end"
.ONESHELL
を使うことで、source
、test.sh
、echo
のコマンドが1つのシェルセッション内で実行されます。.envに定義された環境変数をtest.shに渡すことができます。注意が必要なのは、もしtest.sh
がエラーになった場合、最後のechoは実行されます。
$ make target
start
arg1=1
end
test.shがエラーになったとき、スクリプトを中止したい場合は、以下のように.SHELLFLAGS
を使用します。
.ONESHELL:
SHELL := /bin/bash
.SHELLFLAGS := -e
target:
@echo "start"
source .env
./test.sh "$${TEST_VAL1}"
echo "end"
SAMPLE3: 条件分岐を読みやすく
次に、if文
を使用したシェルスクリプトの例を考えてみます。.ONESHELL
を使うことで、以下のように書けるので読みやすいコードになります。
.ONESHELL:
target:
@VAR1=5
VAR2=10
if [ $${VAR1} -gt $${VAR2} ]; then
echo "VAR1 is greater"
else
echo "VAR2 is greater"
fi
まとめ
このように、.ONESHELL
を活用することで、Makefile内でのシェルスクリプト作成がよりスムーズになります。シンプルな使い方から、少し複雑な処理に至るまで、Makefileの中でシェルスクリプトをうまく使いこなしましょう。
Discussion