एक शेल स्क्रिप्ट को कैसे परिभाषित किया जाए ताकि इसे नहीं चलाया जा सके


40

मैं एक शेल स्क्रिप्ट को परिभाषित कर रहा हूं जिसे उपयोगकर्ता को sourceनिष्पादित करने के बजाय करना चाहिए ।

क्या उपयोगकर्ता के लिए संकेत करने के लिए एक पारंपरिक या बुद्धिमान तरीका है कि यह मामला है, उदाहरण के लिए फ़ाइल एक्सटेंशन के माध्यम से?

क्या शेल कोड है जिसे मैं फ़ाइल में ही लिख सकता हूं, जिसके कारण यह एक संदेश को प्रतिध्वनित कर देगा और इसे छोड़ दिया जाएगा यदि इसे खटास के बजाय निष्पादित किया जाता है, ताकि मैं उपयोगकर्ता को इस स्पष्ट गलती से बचने में मदद कर सकूं?


1
इसलिए, यदि उपयोगकर्ता एक-लाइन शेल स्क्रिप्ट लिख रहा है x, जिसमें सिर्फ कमांड शामिल है . your-script-to-be-sourced, तो यह ठीक है, लेकिन यदि वह निष्पादित करना चाहता है तो bash your-script-to-be-sourcedइसे मना किया जाना चाहिए? इस प्रतिबंध का क्या मतलब है?
user1934428

8
@ user1934428 बेशक। यह एक स्क्रिप्ट के लिए सामान्य है जो कई प्रकार के envचर की गणना करता है और इन्हें डी वास्तविक स्क्रिप्ट के आउटपुट के रूप में छोड़ देता है । एक नौसिखिया पहेली के साथ दिनों के लिए अटक जाएगा यदि आप उन्हें निष्पादित करने की अनुमति देते हैं।
kubanczyk

जवाबों:


45

यह मानते हुए कि आप बैश चल रहे हैं, स्क्रिप्ट की शुरुआत के पास निम्नलिखित कोड डालें जिसे आप खट्टा होना चाहते हैं, लेकिन निष्पादित नहीं किया जा रहा है:

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

बैश के तहत, ${BASH_SOURCE[0]}वर्तमान फ़ाइल का नाम शामिल होगा जिसे शेल पढ़ा जा रहा है या नहीं, चाहे वह खट्टा हो या निष्पादित हो।

इसके विपरीत, $0वर्तमान फ़ाइल का नाम निष्पादित किया जा रहा है।

-efपरीक्षण अगर ये दो फाइलें एक ही फाइल हैं। यदि वे हैं, तो हम उपयोगकर्ता को सतर्क करते हैं और बाहर निकलते हैं।

न तो -efहै और न ही BASH_SOURCEPOSIX हैं। जबकि -efksh, yash, zsh और Dash द्वारा समर्थित है, के BASH_SOURCEलिए bash की आवश्यकता होती है। हालाँकि, इसकेzsh${BASH_SOURCE[0]} द्वारा प्रतिस्थापित किया जा सकता है ${(%):-%N}


2
सीधे शब्दों में echo "Usage: source \"$myfile\""
kubanczyk

6
@kubanczyk sourceपोर्टेबल नहीं है। यह देखते हुए कि यह उत्तर बाश-विशिष्ट है, यह उतना बुरा नहीं है, लेकिन पोर्टेबल का उपयोग करने के लिए यह एक अच्छी आदत है.
gronostaj

33

एक गैर-निष्पादन योग्य फ़ाइल को सॉर्ट किया जा सकता है, लेकिन निष्पादित नहीं किया जाता है, इसलिए, रक्षा की पहली पंक्ति के रूप में, निष्पादन योग्य ध्वज को सेट करना एक अच्छा संकेत होना चाहिए ...

संपादित करें: चाल मैं बस पर ठोकर खाई: शेलंग को किसी भी निष्पादन योग्य बना दें जो शेल दुभाषिया नहीं है, /bin/falseस्क्रिप्ट को एक त्रुटि लौटाता है (आरसी! = 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
पर्ल लिपियों को आम तौर पर नाम दिया गया है somefile.plऔर पायथन के रूप में somefile.py, इसलिए नहीं, मैंने शायद टिप्पणियों को नहीं पढ़ा है (वे, यहां तक ​​कि, वैसे भी?) और bash somefile.shटाइप करने के लिए छोटा है chmod +x somefile.sh; ./somefile.sh...
twalberg

इसके अलावा, कुछ बॉर्न-जैसे गोले भी शामिल हैं bash, जो पहले execveएक फ़ाइल के लिए प्रयास करेंगे , लेकिन अगर वह विफल रहता है, तो वे फ़ाइल का मैन्युअल रूप से निरीक्षण करते हैं और मैन्युअल रूप से व्याख्या करते हैं #!और उस दुभाषिया के माध्यम से आह्वान करते हैं: यह उन दिनों से एक विरासत है जब #!एक शुद्ध उपयोगकर्ता था अधिवेशन, कर्नेल द्वारा ही संभाला जाने के बजाय। मुझे लगता है bash , कम से कम, गैर-निष्पादन योग्य फ़ाइलों के लिए ऐसा नहीं करेंगे , लेकिन मुझे नहीं पता कि यह सभी गोले से इस तरह के समझदार व्यवहार की अपेक्षा करने के लिए पोर्टेबल है कि उपयोगकर्ता से स्क्रिप्ट का आह्वान किया जा सकता है।
mtraceur

"यदि आप जानते हैं कि आप इसे बैश के साथ निष्पादित कर सकते हैं", नहीं, तो कभी-कभी उपयोगकर्ता को अभी पता नहीं है कि इसके अलावा अन्य गोले मौजूद हैं bash और यह bash script.shखतरनाक हो सकता है।
सेर्गेई कोलोडियाज़नी

10

इस स्टैक ओवरफ्लो पोस्ट में कई तरीके सुझाए गए हैं , जिनमें से, मुझे विवान पुरवंतो द्वारा सुझाए गए फंक्शन-आधारित एक और mr.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एक विशेष बैश ऐरे वैरिएबल है, इसमें कॉल स्टैक के अनुरूप सन्निहित सूचकांक होना चाहिए, जब तक कि यह कभी नहीं हो 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

जब आप एक शेल स्क्रिप्ट का स्रोत बनाते हैं , तो शेलबैंग लाइन को अनदेखा कर दिया जाता है। अमान्य शेलबैंग में डालकर, आप उपयोगकर्ता को सचेत कर सकते हैं कि स्क्रिप्ट को गलत तरीके से निष्पादित किया गया था:

#!/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, हालांकि (धन्यवाद @ मुरु!)।


1
एक और नकारात्मक पहलू यह है कि इससे बचाव नहीं होगा bash some/script.sh, जो कि शगुन की अनदेखी भी करेगा।
मूरू

4
आप संदेश को और अधिक स्पष्ट कर सकते हैं #!/bin/echo 'You must source this script!'जैसे कि शेबंग या ऐसा कुछ।
क्रिस

1
@ क्रिस: सही है, लेकिन फिर मैं फ़ाइल प्रकार का पता लगाने (जैसे विम) में खो जाएगा और यह कौन सी बोली का प्रलेखन है। यदि आप इन के बारे में परवाह नहीं करते हैं, तो आपका सुझाव वास्तव में दूसरी स्क्रिप्ट से छुटकारा दिलाएगा!
इंगो करकट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.