Bashシェルスクリプトで「.」や「source」コマンド経由で呼び出されていないかをチェックする方法

はじめに

Bashシェルスクリプトで関数のコールスタックを取得・出力する の続きです。 続きというよりも、当エントリを書きたかったための前振りが上記のエントリです。

実行するシェルスクリプトが、 .source コマンド経由で呼び出された場合には、内部で定義されている 変数関数 がカレントプロセス上に展開されることになります。 スクリプトのファイル内に書かれている 変数関数 が漏れてしまうのを避けるための方法を共有します。

検証環境

1
2
3
4
5
$ uname -moi
x86_64 x86_64 GNU/Linux

$ bash -version | head -n 1
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)

$FUNCNAME 変数をハックする

Bashシェルスクリプトで関数のコールスタックを取得・出力する で見たとおり、 . または source コマンドを使って呼び出されたスクリプトは、 $FUNCNAME 変数のスタックトレース上に source という関数スタックが積まれます。

この仕組みを利用し、 is_sourced という関数を作成し、判定を行います。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/usr/bin/env bash

function is_sourced() {
  [[ "${FUNCNAME[1]}" == "source" ]] && return 0 || return 1
}

# 真の場合は0となり、 `&&` の後ろのコマンドが実行される。
# 偽の場合は1となり、 `&&` の後ろのコマンドは実行されない。
is_sourced \
  && echo '. や source コマンドを使って呼び出してはだめだよ!!'

ひとこと

. または source コマンドを使って呼び出されることを期待する場合には以下のように記述すればOKですね。

1
2
3
4
# 真の場合は0となり、 `||` の後ろのコマンドは実行されない。
# 偽の場合は1となり、 `||` の後ろのコマンドが実行される。
is_sourced \
  || echo '. や source コマンドを使って呼び出してね!!'