क्या बड़ी स्क्रिप्ट को कई स्क्रिप्ट में विभाजित करना और उन्हें मुख्य स्क्रिप्ट में स्रोत बनाना आम है?


23

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

मैंने स्क्रिप्ट को कई लिपियों में विभाजित करने के बारे में सोचा और उन्हें अपनी मुख्य स्क्रिप्ट (अन्य भाषाओं में आयात के समान) में स्रोत बनाया।

लेकिन मुझे आश्चर्य है कि अगर यह एक व्यवहार्य दृष्टिकोण है। पहला, कई स्क्रिप्ट्स को सोर्स करना स्क्रिप्ट की निष्पादन अवधि को गंभीर रूप से धीमा कर सकता है, और दूसरा, यह वितरण को कठिन बनाता है।

तो, क्या यह एक अच्छा तरीका है, और अन्य (ओपन सोर्स) प्रोजेक्ट भी उसी तरह करते हैं?


4
मैं एक बहुत लंबी शेल स्क्रिप्ट की तलाश में था और 3500 लाइनों और 125KB पर था, मैं इसे बनाए रखने की कोशिश नहीं करना चाहता। कार्यक्रमों को हुक करते समय शेल वास्तव में अनुकूल है, लेकिन जब यह गणना करने की कोशिश करता है, तो यह बहुत बदसूरत हो जाता है। मुझे पता है कि आपके पास अधिकतर कोड काम करते हैं और इसे पोर्ट करने की लागत अधिक है, लेकिन आप भविष्य में कुछ और विचार कर सकते हैं।
एमएसडब्ल्यू

1
मैं एक ही समस्या में चला गया हूँ। मेरे पास मध्यम बड़े बैश प्रोजेक्ट sourceforge.net/projects/duplexpr हैं । वर्तमान में, प्रत्येक स्क्रिप्ट स्वयं समाहित है, लेकिन मैं सभी सामान्य कार्यों को एक अलग फ़ाइल (एस) में ले जाने और उन्हें शामिल करने के बारे में सोच रहा हूं जहां उन्हें कई स्थानों पर अपडेट करने के लिए समाप्त करने की आवश्यकता है। सामान्य तौर पर, मुझे लगता है कि इसे स्रोत के बजाय प्रत्येक क्रमिक स्क्रिप्ट को कॉल करना बेहतर होगा। यह भागों को स्वतंत्र रूप से चलाना संभव बनाता है। फिर, आपको चर को तर्क के रूप में या पैरामीटर फ़ाइलों में पास करना होगा (या आप बस उन्हें निर्यात कर सकते हैं यदि आप स्टैंडअलोन नहीं चाहते हैं।)
जो

जवाबों:


13

हां, यह एक आम बात है। उदाहरण के लिए, यूनिक्स के शुरुआती दिनों में अपने बूट चरणों से लेकर मल्टीसियर ऑपरेशन तक सिस्टम को निर्देशित करने के लिए जिम्मेदार शेल कोड एक सिंगल फाइल था /etc/rc। आज बूट प्रक्रिया को कई शेल स्क्रिप्ट द्वारा नियंत्रित किया जाता है, जो फ़ंक्शन से टूट जाती है, केंद्रीय कार्यों से आवश्यकतानुसार सामान्य कार्यों और चर के साथ। लिनक्स वितरण, मैक, बीएसडी, सभी ने अलग-अलग डिग्री के लिए इस दृष्टिकोण को अपनाया है।


2
हालांकि उस मामले में, यह पुन: प्रयोज्य के लिए अधिक है। विभिन्न लिपियाँ शेल फ़ंक्शंस की एक सामान्य लाइब्रेरी का उपयोग करती हैं।
स्टीफन चेजेलस

16

क्या उस बिंदु पर नौकरी के लिए सही उपकरण है? एक डेवलपर के रूप में जो आउटगोइंग कोड के मुद्दों से टकराए हुए हैं, मैं आपको बता सकता हूं कि एक पुनर्लेखन पर विचार नहीं किया जाना चाहिए, बल्कि आप अपने आवेदन को बढ़ने के लिए जिस पैमाने पर देख रहे हैं उसके लिए बेहतर अनुकूल कुछ टुकड़ों को अलग करने पर विचार करें - शायद अजगर या रूबी या यहां तक ​​कि पर्ल ?

शेल एक उपयोगिता भाषा है - यह एक स्क्रिप्टिंग भाषा है - और इसलिए इसे उन आकारों में विकसित करना कठिन होगा।


यह वही है जो मैं पोस्ट करने वाला था।
zwol

विशेष रूप से यह देखते हुए कि सोलारिस जैसे पुराने ओएस भी पर्ल, और अजगर, आदि के साथ शिपिंग कर रहे हैं। शेल स्क्रिप्ट का उपयोग करने का एक कारण यह है कि शेल को हमेशा उपलब्ध रहने की गारंटी दी गई थी, लेकिन एचपी-यूएक्स और सोलारिस और एआईएक्स जैसे बड़े यूनिक्स को अन्य उपकरणों को शामिल करने की गारंटी नहीं दी जा सकती है।
टिम केनेडी

7

यदि यह आपके रखरखाव को आसान बनाता है, तो आपके पास दोनों हो सकते हैं। इसे तार्किक भागों में विभाजित करें ताकि आप इसे आसानी से बनाए रख सकें, फिर लिखें (उदाहरण के लिए, इसे वापस वितरण के लिए एक साथ रखने के लिए एक मेकफाइल। आप कुछ त्वरित स्क्रिप्ट को शामिल कर सकते हैं ताकि कार्यों को शामिल करने से लेकर फाइल तक आउटपुट फाइल में शामिल किया जा सके। sourceलाइन या बस कुछ इस तरह तुच्छ कर (यदि आप इस फिर से tabify करना होगा के रूप में makeटैब की आवश्यकता है):

all: myscript

myscript: includes/* body/*
    cat $^ > "$@" || (rm -f "$@"; exit 1)

फिर आपके पास "स्रोत" संस्करण (संपादन के लिए उपयोग किया जाता है) और "बाइनरी" संस्करण (तुच्छ स्थापना के लिए उपयोग किया जाता है)।


1
अहा! कोई और जो सरल बिल्ली दृष्टिकोण का उपयोग करता है :)
क्लेटन स्टेनली

4

एक स्क्रिप्ट टूट सकती है जैसा कि आप वर्णन करते हैं - बस कुछ भी किया जा सकता है। मैं कहूंगा कि 'अच्छी अप्रोच' आपकी बड़ी स्क्रिप्ट को कंपेयर करने के लिए होगी, यह पता लगाने के लिए कि इसके हिस्सों को एक अलग प्रक्रिया के रूप में कैसे चलाया जा सकता है, आईपीसी तंत्र के माध्यम से संचार करता है।

इसके अलावा, शेल स्क्रिप्ट के लिए, मैं इसे एक सिंगल फाइल के रूप में पैकेज करूंगा। जैसा कि आप कहते हैं, यह वितरण को कठिन बनाता है: आपको या तो यह जानना होगा कि 'लाइब्रेरी' स्क्रिप्ट कहाँ स्थित हैं - शेल स्क्रिप्ट के लिए कोई अच्छा मानक नहीं है - या उपयोगकर्ता पर भरोसा करते हुए अपना रास्ता सही तरीके से सेट करें।

आप एक अधिष्ठापन प्रोग्राम वितरित कर सकते हैं जो आपके लिए यह सब संभालता है, फ़ाइलों को निकालना, उन्हें उचित स्थान पर रखना, उपयोगकर्ता को export PROGRAMDIR=$HOME/lib/PROGRAM~ / .bashrc फ़ाइल की तरह कुछ जोड़ने के लिए कहना । तब मुख्य प्रोग्राम विफल हो सकता है अगर $PROGRAMDIRसेट नहीं है या आपके द्वारा अपेक्षित फ़ाइलों में शामिल नहीं है।

मैं अन्य लिपियों को लोड करने के ओवरहेड के बारे में ज्यादा चिंता नहीं करूंगा। ओवरहेड वास्तव में सिर्फ एक फ़ाइल खोल रहा है; पाठ का प्रसंस्करण समान है, खासकर यदि वे फ़ंक्शन परिभाषा हैं।


1

सामान्य अभ्यास या नहीं, मुझे नहीं लगता कि निर्यात के एक सेट के अलावा कुछ भी सोर्स करना एक अच्छा विचार है। मुझे लगता है कि सोर्सिंग द्वारा कोड निष्पादित करना सिर्फ भ्रम की स्थिति है, और यह फिर से उपयोग को सीमित करता है, क्योंकि पर्यावरण और अन्य चर सेटिंग्स सोर्सिंग कोड पर बहुत अधिक निर्भर कोड बनाती हैं।

आप अपने एप्लिकेशन को छोटी, स्व-निहित स्क्रिप्ट में तोड़ने के लिए बेहतर हैं, फिर उन्हें कमांड की एक श्रृंखला के रूप में निष्पादित करें। यह डिबगिंग को कम करेगा, क्योंकि आप प्रत्येक प्रोग्राम के बीच एक इंटरेक्टिव शेल में प्रत्येक स्व-निहित स्क्रिप्ट को निष्पादित कर सकते हैं, फाइलों, लॉग्स आदि की जांच कर सकते हैं। आपकी एकल, बड़ी एप्लिकेशन स्क्रिप्ट स्क्रिप्ट को नियंत्रित करने वाली सरलता में बदल जाती है जो आपके द्वारा डीबगिंग समाप्त करने के बाद बस कमांड की एक श्रृंखला चलाती है।

छोटी, स्व-निहित स्क्रिप्ट का एक समूह कठिन-से-स्थापित समस्या में चलता है।


1

लिपियों की सोर्सिंग का एक विकल्प बस उन्हें तर्कों के साथ बुला रहा है। यदि आप पहले से ही अपनी अधिकांश कार्यक्षमता को शेल फ़ंक्शंस में तोड़ चुके हैं, तो आप संभवतः पहले से ही ऐसा करने में सक्षम होने के काफी करीब हैं। बैश के निम्नलिखित स्निपेट को स्क्रिप्ट में घोषित किसी भी फ़ंक्शन को एक उपकमांड के रूप में उपयोग करने की अनुमति देता है:

if [[ ${1:-} ]] && declare -F | cut -d' ' -f3 | fgrep -qx -- "${1:-}"
then "$@"
else main "$@" # Try the main function if args don't match a declaration.
fi

इसका कारण sourceपर्यावरण और विकल्प प्रदूषण से बचना है।


0

यहाँ मेरा उदाहरण है कि कैसे एक बड़ी बैश स्क्रिप्ट को कई फाइलों में विभाजित किया जा सकता है और फिर एक परिणामी स्क्रिप्ट में बनाया जा सकता है: https://github.com/zinovyev/bash-project

मैं Makefileइस उद्देश्य के लिए उपयोग करता हूं :

TARGET_FILE = "target.sh"
PRJ_SRC = "${PWD}/src/main.sh"
PRJ_LIB = $(shell ls -d ${PWD}/lib/*) # All files from ./lib

export PRJ_LIB

SHELL := /bin/env bash
all: define_main add_dependencies invoke_main

define_main:
    echo -e "#!/usr/bin/env bash\n" > ${TARGET_FILE}
    echo -e "function main() {\n" >> ${TARGET_FILE}
    cat "${PRJ_SRC}" | sed -e 's/^/  /g' >> ${TARGET_FILE}
    echo -e "\n}\n" >> ${TARGET_FILE}

invoke_main:
    echo "main \$$@" >> ${TARGET_FILE}

add_dependencies:
    for filename in $${PRJ_LIB[*]}; do cat $${filename} >> ${TARGET_FILE}; echo >> ${TARGET_FILE}; done
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.