ユーザーが実行する必要があるシェルスクリプトを定義しています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
。-ef
ksh、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
ただし、正しい通話深さを得るには、現地通貨の深さを知るか計算する必要があります。他の関数やスクリプトから発生するスクリプトと同じ状況では、配列(スタック)がより深くなります。 (FUNCNAME
neverでない限り、呼び出しスタックに対応する連続インデックスを持つ必要がある特別な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
ファイルをインポートしていない限り、関数の外部にゼロ以外の終了コードを使用してください。