実行されないソースとなるシェルスクリプトを定義する方法


40

ユーザーsourceが実行するのではなく、シェルスクリプトを定義しています。

たとえばファイル拡張子を使用して、これが事実であることをユーザーに示唆する従来の方法またはインテリジェントな方法はありますか?

ファイル自体に書き込むことができるシェルコードはありますか?これにより、ソースの代わりにメッセージがエコーされ、実行されると終了するため、ユーザーがこの明らかな間違いを避けるのを助けることができますか?


1
だから、ユーザーがxコマンドを含む1行のシェルスクリプトを書いている場合. your-script-to-be-sourced、それはOKですが、彼がbash your-script-to-be-sourcedそれを実行したい場合は禁止されるべきですか?この制限のポイントは何ですか?
user1934428

8
@ user1934428もちろんです。これは、env変数の数を計算し、これらを事実上のスクリプトの出力として残すスクリプトでは正常です。あなたが彼らに実行を許可するならば、初心者はパズルで数日間動けなくなるでしょう。
クバンチク

回答:


45

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これら2つのファイルが同じファイルかどうかをテストします。存在する場合、ユーザーに警告して終了します。

POSIX -efでもBASH_SOURCEありません。一方で-efkshの、ヤシュ、zshのとダッシュでサポートされて、BASH_SOURCEbashのを必要とします。 ではzsh、ただし、${BASH_SOURCE[0]}置き換えることができます${(%):-%N}


2
単に echo "Usage: source \"$myfile\""
クバンチク

6
@kubanczyk sourceは移植性がありません。この回答はbash固有のものであることを考えると、それほど悪くはありませんが、ポータブルを使用するのは良い習慣.
です-gronostaj

33

非実行可能ファイルはソースにできますが、実行できません。そのため、防御の第一線として、実行可能フラグを設定しないことが良いヒントになるはずです...

編集:私はつまずいたトリック:シェバンをシェルインタープリターではない実行可能ファイルにし/bin/false、スクリプトにエラーを返します(rc!= 0)

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

7
しかし、非実行可能ファイルは、まだ経由して例えば実行することができますbash somefile.sh...
twalberg

1
bash(vd perl、python、awk ...)で実行できることがわかっている場合は、ソースを見て、それをしないようにというコメントを見ました:)
xenoid

1
Perlスクリプトは、一般的に命名されていないsomefile.plようとPython somefile.pyので全く、私はおそらくのコメントを読んでいない、(何でも、とにかく、それらのですか?)とbash somefile.sh比べて入力する短いchmod +x somefile.sh; ./somefile.sh...
twalberg

また、などの一部のBourneのようなシェルbashは最初にexecveファイルを試行しますが、それが失敗した場合、ファイルを手動で検査し、#!そのインタープリターを介して手動で解釈して呼び出します:これは#!、純粋にユーザースペースだった時代からの遺産ですカーネル自体によって処理される代わりに、慣例に従ってください。私が考えて bash、少なくとも、うではない非実行可能ファイルに対してこの操作を行うが、それは、ユーザからスクリプトを起動するかもしれないことをすべてのシェルからそのようなまともな行動を期待するポータブルだ場合、私は知りません。
mtraceur

「bashで実行できることがわかっている場合」ええと、いや、ユーザーは、他のシェルが存在することbash や、bash script.sh危険な可能性があることを知らないことがあります。
セルギーKolodyazhnyy

10

このStack Overflowの投稿で提案されているいくつかの方法がありますが、そのうち、Wirawan Purwantomr.spuraticが提案した関数ベースの方法が最も気に入りました

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特別な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

7

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

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

スクリプトの最後までreturn関数の外部には、ファイルがソースされていない限り、ゼロ以外の終了コードがあります。


3
これは0の終了ステータスを返すことに注意してください。私が代わりに使用するこの同様のイディオムを試してくださいreturn 2>/dev/null; echo "$0: This script must be sourced" 1>&2; exit 1
。– wjandrea

5

シェルスクリプトのソースを作成すると、shebang行は無視されます。無効なシバンを入れることで、スクリプトが誤って実行されたことをユーザーに警告できます。

#!/bin/bash source-this-script
# ...

エラーメッセージは次のようになります。

/bin/bash: source-this-script: No such file or directory

(任意の)引数名はすでに強力なヒントを提供しますが、エラーメッセージは100%明確ではありません。次の場所にあるユーティリティスクリプトsource-this-scriptでこれを修正できますPATH

#!/bin/sh
echo >&2 "This script must be sourced, not executed${1:+: }${1:-!}"
exit 1

エラーメッセージは次のようになります。

This script must be sourced, not executed: path/to/script.sh

他のアプローチとの比較

他の回答と比較して、このアプローチは各スクリプトへの最小限の変更のみを必要とします(また、シェバン行を使用すると、エディターでのファイルタイプの検出に役立ち、シェルスクリプトの方言が指定されるため、メリットもあります)。欠点は、やや不明瞭なエラーメッセージ、または別のシェルスクリプトの(一度限りの)追加です。

bash path/to/script.shただし、による明示的な呼び出しは妨げられません(@muruに感謝します!)。


1
もう1つの欠点は、これがに対して保護されないことbash some/script.shです。これにより、シバンも無視されます。
ムル

4
あなたは、シバン#!/bin/echo 'You must source this script!'またはそのような何かをすることによって、メッセージをより明確にすることができます。
クリス

1
@Chris:でも、そうすると、ファイルタイプの検出(Vimなど)と、これがどのシェル方言であるかのドキュメントを失います。これらを気にしない場合、あなたの提案は確かに2番目のスクリプトを取り除きます!
インゴカルカット
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.