インポートするが実行しないシェルスクリプトを定義する方法

インポートするが実行しないシェルスクリプトを定義する方法

ユーザーが実行する必要があるシェルスクリプトを定義していますsource

ファイル拡張子を介してユーザーにこの状況を警告する従来の方法または賢明な方法はありますか?

ファイルをインポートするのではなく実行すると、メッセージをエコーし​​て終了し、ユーザーがこの明白なエラーを回避するためにファイル自体に書き込むことができるシェルコードはありますか?

答え1

bashを実行していると仮定し、インポートするが実行したくないスクリプトの冒頭に次のコードを配置します。

if [ "${BASH_SOURCE[0]}" -ef "$0" ]
then
    echo "Hey, you should source this script, not execute it!"
    exit 1
fi

bashの下には、${BASH_SOURCE[0]}シェルが読み込んでいる現在のファイルの名前が含まれています(インポート中でも実行中でも)。

一方、$0現在実行中のファイルの名前です。

-ef両方のファイルが同じファイルかどうかをテストします。その場合は、ユーザーに警告してログアウトします。

POSIXも同様-efですBASH_SOURCE-efksh、yash、zsh、Dashはサポートされていますが、bashBASH_SOURCEが必要です。 存在するzshただし、${BASH_SOURCE[0]}に置き換えることができます${(%):-%N}

答え2

実行不可能なファイルを取得することはできますが、実行できないので、最初の防御線として実行可能フラグを設定しない方が良いヒントになります。

編集:ちょうど偶然発見したトリック:シェルインタプリタではなく実行可能ファイルをshebangにすると、スクリプトは/bin/falseエラー(rc!= 0)を返します。

#!/bin/false "This script should be sourced in a shell, not executed directly"

答え3

いくつかの方法が提案されている。このスタックオーバーフロー投稿、その中で私は機能ベースの提案が好きです。ウィラバン・プワントそしてスプラティック氏最高:

Wirawan Purwantoが提案したように、最も信頼できる方法は確認することです。 FUNCNAME[1] 内部関数:

function mycheck() { declare -p FUNCNAME; }
mycheck

それから:

$ bash sourcetest.sh
declare -a FUNCNAME='([0]="mycheck" [1]="main")'
$ . sourcetest.sh
declare -a FUNCNAME='([0]="mycheck" [1]="source")'

callerこれは、出力値を確認し、main呼び出しsource元のコンテキストを区別するのと同じです。を使用すると、出力をキャプチャして解析する時間をFUNCNAME[]節約できます。callerただし、正しい通話深さを得るには、現地通貨の深さを知るか計算する必要があります。他の関数やスクリプトから発生するスクリプトと同じ状況では、配列(スタック)がより深くなります。 (FUNCNAMEneverでない限り、呼び出しスタックに対応する連続インデックスを持つ必要がある特別なbash配列変数です。unset

したがって、スクリプトの先頭に以下を追加できます。

function check()
{
    if [[ ${FUNCNAME[-1]} != "source" ]]   # bash 4.2+, use ${FUNCNAME[@]: -1} for older
    then
        printf "Usage: source %s\n" "$0"
        exit 1
    fi
}
check

答え4

スクリプトの実行が有害ではなく役に立たないと仮定すると、以下を追加できます。

return 0 || printf 'Must be sourced, not executed\n' >&2

到着終わりスクリプト済み。returnファイルをインポートしていない限り、関数の外部にゼロ以外の終了コードを使用してください。

関連情報