2012-10-10 12 views
31

मेरे पास एक शेल स्क्रिप्ट है जिसे मैं शुनिट के साथ परीक्षण करना चाहता हूं। स्क्रिप्ट (और सभी फ़ंक्शंस) एक फ़ाइल में हैं क्योंकि यह इंस्टॉलेशन को अधिक आसान बनाता है।शैल स्क्रिप्ट से फ़ंक्शन आयात करना

के लिए उदाहरण script.sh

#!/bin/sh 

foo() { ... } 
bar() { ... } 

code 

मैं (है कि वितरित किया गया और स्थापित करने की जरूरत नहीं है)

run_tests.sh

#!/bin/sh 

. script.sh 

# Unit tests 
तरह कार्यों script.sh में परिभाषित किया गया परीक्षण करने के लिए एक दूसरे फ़ाइल लिखना चाहते थे

अब समस्या . (या) में निहित है बैश में)। यह न केवल फ़ंक्शन परिभाषाओं को पार्स करता है बल्कि स्क्रिप्ट में कोड निष्पादित करता है।

कोई तर्क के साथ स्क्रिप्ट के बाद से बुरा कुछ नहीं करता है मैं कर सकता

. script.sh > /dev/null 2>&1 

लेकिन यदि मेरा लक्ष्य को प्राप्त करने के लिए एक बेहतर तरीका है मैं भटक रहा था।

संपादित

मेरे प्रस्तावित वैकल्पिक हल के मामले में काम नहीं करता है sourced स्क्रिप्ट कॉल exit तो मैं जाल को

#!/bin/sh 

trap run_tests ERR EXIT 

run_tests() { 
    ... 
} 

. script.sh 

run_tests समारोह कहा जाता है से बाहर निकलें है लेकिन जैसे ही मैं पुनः प्रेषण स्रोत कमांड का आउटपुट स्क्रिप्ट में फ़ंक्शंस को पार्स नहीं किया जाता है और ट्रैप हैंडलर

यह काम करता है लेकिन मुझे आउटपुट मिलता है script.sh की ut:

#!/bin/sh 
trap run_tests ERR EXIT 
run_tests() { 
    function_defined_in_script_sh 
} 
. script.sh 

यह आउटपुट मुद्रित नहीं करता, लेकिन मैं एक त्रुटि है कि कार्य निर्धारित नहीं है मिलती है:

#!/bin/sh 
trap run_tests ERR EXIT 
run_tests() { 
    function_defined_in_script_sh 
} 
. script.sh | grep OUTPUT_THAT_DOES_NOT_EXISTS 

यह आउटपुट और run_tests जाल हैंडलर प्रिंट नहीं करता नहीं बुलाया जाता है सब पर:

#!/bin/sh 
trap run_tests ERR EXIT 
run_tests() { 
    function_defined_in_script_sh 
} 
. script.sh > /dev/null 

उत्तर

39

bash manpage की "शैल अंतर्निहित कमांड" अनुभाग में, . उर्फ ​​012 के अनुसारउन तर्कों की एक वैकल्पिक सूची लेता है जो स्क्रिप्ट के लिए पारित किए जाते हैं। आप इसे एक-कुछ भी विकल्प पेश करने के लिए उपयोग कर सकते हैं। उदाहरण के लिए, script.sh हो सकता है:

#!/bin/sh 

foo() { 
    echo foo $1 
} 

main() { 
    foo 1 
    foo 2 
} 

if [ "${1}" != "--source-only" ]; then 
    main "${@}" 
fi 

और unit.sh हो सकता है:

#!/bin/bash 

. ./script.sh --source-only 

foo 3 

फिर script.sh सामान्य रूप से व्यवहार करेंगे, और unit.shscript.sh से सभी कार्यों के लिए उपयोग होगा लेकिन main() कोड आह्वान नहीं होंगे ।

ध्यान दें कि source करने के लिए अतिरिक्त तर्क POSIX में नहीं हैं, इसलिए /bin/shunit.sh के शुरू में यह इसलिए संभाल नहीं सकता #!/bin/bash

+1

आप चाहते हो सकता है के लिए 'shift' तर्क सूची तो' 'main' --source के साथ संपर्क में नहीं मिलता है -ऑनली ' –

+0

@ हबर्टग्रेज़कोवियाक अच्छा बिंदु, तय। सलाह के लिये धन्यवाद! – andrewdotn

+1

'शिफ्ट' वहां समझ में नहीं आता है, क्योंकि 'मुख्य' केवल तभी चलता है जब '- स्रोत-केवल' ** ** पहला तर्क नहीं है। –

16

अजगर से इस तकनीक को आकर्षित किया, लेकिन अवधारणा बैश या किसी अन्य खोल में बस ठीक काम करता है ...

विचार यह है कि हम एक समारोह में हमारी स्क्रिप्ट का मुख्य कोड अनुभाग बारी है। फिर स्क्रिप्ट के बहुत अंत में, हमने एक 'if' कथन रखा है जो केवल उस फ़ंक्शन को कॉल करेगा यदि हमने स्क्रिप्ट निष्पादित की लेकिन हम इसे सोर्स नहीं करते हैं। फिर हम स्पष्ट रूप से स्क्रिप्ट() फ़ंक्शन को हमारी 'रनटेस्ट्स' स्क्रिप्ट से कॉल करते हैं, जिसने 'स्क्रिप्ट' स्क्रिप्ट को सोर्स किया है और इस प्रकार उसके सभी कार्यों को शामिल किया गया है।

इस तथ्य यह है कि अगर हम स्क्रिप्ट स्रोत, बैश से बनाए रखा वातावरण चर $0, जो स्क्रिप्ट के नाम निष्पादित किया जा रहा है, बुला (पैरेंट) स्क्रिप्ट का नाम होगा पर निर्भर करता है (runtests में यह मामला), सोर्सड स्क्रिप्ट नहीं।

(मैं script.sh नाम बदला है बस का कारण script को .sh अनावश्यक है और मुझे confuses। :-)

नीचे दो लिपियों रहे हैं। कुछ नोट ...

  • [email protected] तर्क समारोह या अलग-अलग तारों के रूप में स्क्रिप्ट के लिए पारित सभी के लिए मूल्यांकन करता है। यदि इसके बजाय, हमने $* का उपयोग किया, तो सभी तर्क एक स्ट्रिंग में एक साथ संयोजित किए जाएंगे।
  • RUNNING="$(basename $0)"$0 के बाद से आवश्यक है कम से कम वर्तमान निर्देशिका उपसर्ग ./script में शामिल है।
  • परीक्षण if [[ "$RUNNING" == "script" ]]...। वह जादू है जो script को स्क्रिप्ट() फ़ंक्शन को कॉल करने के लिए केवल script को कमांडलाइन से सीधे चलाता है।

स्क्रिप्ट

#!/bin/bash 

foo() { echo "foo()"; } 

bar() { echo "bar()"; } 

script() { 
    ARG1=$1 
    ARG2=$2 
    # 
    echo "Running '$RUNNING'..." 
    echo "script() - all args: [email protected]" 
    echo "script() -  ARG1: $ARG1" 
    echo "script() -  ARG2: $ARG2" 
    # 
    foo 
    bar 
} 

RUNNING="$(basename $0)" 

if [[ "$RUNNING" == "script" ]] 
then 
    script "[email protected]" 
fi 

runtests

#!/bin/bash 

source script 

# execute 'script' function in sourced file 'script' 
script arg1 arg2 arg3 
+1

इसमें दो डाउनसाइड्स हैं: जब भी आप स्क्रिप्ट का नाम बदलते हैं, तो आपको इसकी सामग्री बदलनी होगी; और यह सिम्लिंक के साथ काम नहीं करता है (उपनामों के बारे में निश्चित नहीं है)। –

3

आप बैश, @ andrewdotn का दृष्टिकोण करने के लिए एक ऐसी ही समाधान का उपयोग कर रहे हैं (लेकिन एक अतिरिक्त ध्वज की आवश्यकता होगी, या के आधार पर बिना स्क्रिप्ट नाम) BASH_SOURCE सरणी का उपयोग करके पूरा किया जा सकता है।

script.sh:

#!/bin/bash 

foo() { ... } 
bar() { ... } 

main() { 
    code 
} 

if [[ "${#BASH_SOURCE[@]}" -eq 1 ]]; then 
    main "[email protected]" 
fi 

run_tests.sh:

#!/bin/bash 

. script.sh 

# Unit tests 
संबंधित मुद्दे