फ़ंक्शन में संपूर्ण बैश स्क्रिप्ट क्यों लिखी जाती है?


59

काम पर, मैं बार-बार स्क्रिप्ट लिखता हूं। मेरे पर्यवेक्षक ने सुझाव दिया है कि संपूर्ण स्क्रिप्ट को निम्नलिखित उदाहरणों के समान कार्यों में विभाजित किया जा सकता है:

#!/bin/bash

# Configure variables
declare_variables() {
    noun=geese
    count=three
}

# Announce something
i_am_foo() {
    echo "I am foo"
    sleep 0.5
    echo "hear me roar!"
}

# Tell a joke
walk_into_bar() {
    echo "So these ${count} ${noun} walk into a bar..."
}

# Emulate a pendulum clock for a bit
do_baz() {
    for i in {1..6}; do
        expr $i % 2 >/dev/null && echo "tick" || echo "tock"
        sleep 1
    done
}

# Establish run order
main() {
    declare_variables
    i_am_foo
    walk_into_bar
    do_baz
}

main

क्या "पठनीयता" के अलावा ऐसा करने का कोई कारण है, जो मुझे लगता है कि कुछ और टिप्पणियों और कुछ लाइन रिक्ति के साथ समान रूप से स्थापित किया जा सकता है?

क्या यह स्क्रिप्ट को अधिक कुशलता से चलाता है (मैं वास्तव में विपरीत, अगर कुछ भी) की उम्मीद करूंगा, या क्या यह उपरोक्त पठनीयता क्षमता से परे कोड को संशोधित करना आसान बनाता है? या यह वास्तव में सिर्फ एक शैलीगत पसंद है?

कृपया ध्यान दें कि यद्यपि स्क्रिप्ट इसे अच्छी तरह से प्रदर्शित नहीं करती है, लेकिन हमारी वास्तविक लिपियों में कार्यों का "रन ऑर्डर" बहुत रैखिक होता है - walk_into_barयह उस सामान पर निर्भर करता है जो i_am_fooउसने किया है, और इसके do_bazद्वारा निर्धारित सामान पर कार्य करता है walk_into_bar- इसलिए किया जा रहा है मनमाने ढंग से रन ऑर्डर स्वैप करने में सक्षम कुछ ऐसा नहीं है जो हम आम तौर पर कर रहे हैं। उदाहरण के लिए, यदि आप अचानक डाल करने के लिए नहीं चाहते हैं declare_variablesके बाद walk_into_bar, कि चीजें टूट जाएगा।

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

#!/bin/bash

# Configure variables
noun=geese
count=three

# Announce something
echo "I am foo"
sleep 0.5
echo "hear me roar!"

# Tell a joke
echo "So these ${count} ${noun} walk into a bar..."

# Emulate a pendulum clock for a bit
for i in {1..6}; do
    expr $i % 2 >/dev/null && echo "tick" || echo "tock"
    sleep 1
done

30
मुझे आपका बॉस पसंद है। अपनी लिपियों में मैं इसे main()सबसे ऊपर रखता हूं और main "$@"इसे कॉल करने के लिए सबसे नीचे जोड़ता हूं । जब आप इसे खोलते हैं तो आपको पहली बार उच्च स्तरीय स्क्रिप्ट तर्क दिखाई देता है।
जॉन कुगेलमैन

22
मैं इस धारणा से असहमत हूं कि पठनीयता "कुछ और टिप्पणियों और कुछ लाइन रिक्ति के साथ समान रूप से अच्छी तरह से स्थापित हो सकती है।" शायद कल्पना के अलावा, मैं एक ऐसी पुस्तक से निपटना नहीं चाहूंगा जिसमें प्रत्येक अध्याय और अनुभाग के लिए सामग्री और वर्णनात्मक नामों की तालिका नहीं है। प्रोग्रामिंग भाषाओं में, यह पठनीयता है कि कार्य प्रदान कर सकता है, और टिप्पणी नहीं कर सकता है।
रयूमाइड सिप

6
ध्यान दें कि फ़ंक्शंस में घोषित चर घोषित किए जाने चाहिए local- यह वैरिएबल स्कोप प्रदान करता है जो कि किसी भी गैर-तुच्छ लिपि में अविश्वसनीय रूप से महत्वपूर्ण है।
बोरिस स्पाइडर

8
मैं आपके बॉस से असहमत हूं। यदि आपको अपनी स्क्रिप्ट को फ़ंक्शन में तोड़ना है, तो संभवतः आपको पहली बार शेल स्क्रिप्ट नहीं लिखनी चाहिए। इसके बजाय एक कार्यक्रम लिखें।
el.pescado

6
फ़ंक्शंस उन प्रक्रियाओं के लिए होती हैं, जिन्हें स्क्रिप्ट के भीतर या एक से अधिक स्क्रिप्ट में दोहराया जाता है। वे समान कार्यप्रणाली को भी लागू करने की अनुमति देते हैं। उदाहरण के लिए syslog लिखने के लिए एक फ़ंक्शन का उपयोग करना। जब तक हर कोई समान फ़ंक्शन का उपयोग करता है, तब तक आपकी syslog प्रविष्टियाँ अधिक सुसंगत होती हैं। आपके उदाहरण जैसे एकल उपयोग फ़ंक्शन स्क्रिप्ट को अनावश्यक रूप से जटिल करते हैं। कुछ मामलों में, वे मुद्दों (चर स्कोपिंग) का परिचय देते हैं।
Xalorous

जवाबों:


39

मैंने काफिर लवी के ब्लॉग पोस्ट "रक्षात्मक बैश प्रोग्रामिंग" को पढ़ने के बाद बैश प्रोग्रामिंग की इसी शैली का उपयोग करना शुरू कर दिया है । वह कुछ अच्छे कारण देता है, लेकिन व्यक्तिगत रूप से मुझे ये सबसे महत्वपूर्ण लगते हैं:

  • प्रक्रियाएं वर्णनात्मक हो जाती हैं: यह पता लगाना बहुत आसान है कि कोड का एक विशेष भाग क्या करना चाहिए। कोड की दीवार के बजाय, आप देखते हैं "ओह, find_log_errorsफ़ंक्शन त्रुटियों के लिए लॉग फ़ाइल को पढ़ता है"। इसकी तुलना बहुत सारे awk / grep / sed लाइनों से करने से होती है जो भगवान का उपयोग करते हैं और जानते हैं कि एक लंबी स्क्रिप्ट के बीच में किस प्रकार का रेगेक्स है - आपको कोई अंदाजा नहीं है कि जब तक वहाँ कोई टिप्पणी नहीं होती है।

  • आप set -xऔर में संलग्न करके कार्यों को डीबग कर सकते हैं set +x। एक बार जब आप जानते हैं कि बाकी कोड ठीक काम करता है, तो आप इस ट्रिक का उपयोग केवल उस विशिष्ट फ़ंक्शन को डिबगिंग पर ध्यान केंद्रित करने के लिए कर सकते हैं। ज़रूर, आप स्क्रिप्ट के कुछ हिस्सों को संलग्न कर सकते हैं, लेकिन क्या होगा अगर यह एक लंबा हिस्सा है? इस तरह से कुछ करना आसान है:

     set -x
     parse_process_list
     set +x
  • के साथ मुद्रण उपयोग cat <<- EOF . . . EOF। मैंने अपने कोड को और अधिक पेशेवर बनाने के लिए इसका कई बार उपयोग किया है। इसके अलावा, फ़ंक्शन के parse_args()साथ getoptsकाफी सुविधाजनक है। फिर, यह पाठ की विशाल दीवार के रूप में स्क्रिप्ट में सब कुछ shoving के बजाय पठनीयता के साथ मदद करता है। इनका पुन: उपयोग करना भी सुविधाजनक है।

और जाहिर है, यह किसी ऐसे व्यक्ति के लिए बहुत अधिक पठनीय है जो सी या जावा, या वाल्हा जानता है, लेकिन सीमित बैश अनुभव है। जहाँ तक दक्षता जाती है, वहाँ बहुत कुछ नहीं है जो आप कर सकते हैं - अपने आप को सबसे कुशल भाषा नहीं है और लोग गति और दक्षता के लिए पर्ल और अजगर पसंद करते हैं। हालांकि, आप niceएक समारोह कर सकते हैं:

nice -10 resource_hungry_function

कोड की प्रत्येक पंक्ति पर अच्छा कॉल करने की तुलना में, यह बहुत सारी टाइपिंग को कम कर देता है और इसे आसानी से उपयोग किया जा सकता है जब आप अपनी स्क्रिप्ट का केवल एक हिस्सा चाहते हैं जो कम प्राथमिकता के साथ चले।

पृष्ठभूमि में चल रहे कार्य, मेरी राय में, तब भी मदद करते हैं जब आप पृष्ठभूमि में चलाने के लिए बयानों का पूरा गुच्छा रखना चाहते हैं।

कुछ उदाहरण जहां मैंने इस शैली का उपयोग किया है:


3
मुझे यकीन नहीं है कि आपको उस लेख से किसी भी सुझाव को बहुत गंभीरता से लेना चाहिए। दी, यह कुछ अच्छे विचार हैं, लेकिन यह स्पष्ट रूप से किसी को स्क्रिप्टिंग के लिए इस्तेमाल नहीं किया गया है। किसी भी उदाहरण में एक भी वैरिएबल उद्धृत नहीं किया गया है! इस उत्तर में आपके बिंदु समझ में आते हैं, लेकिन जुड़ा हुआ लेख किसी ऐसे व्यक्ति द्वारा लिखा गया लगता है, जो सिर्फ अन्य भाषाओं के लिए उपयोग किया जाता है और बैश पर अपनी शैली को मजबूर करने की कोशिश कर रहा है।
terdon

1
@terdon मैं इस लेख पर वापस गया और इसे फिर से पढ़ा। एकमात्र स्थान जहां लेखक ऊपरी मामले चर नामकरण का उल्लेख करता है, "अपरिवर्तनीय वैश्विक चर" में है। यदि आप वैश्विक चरों पर विचार करते हैं, जो फ़ंक्शन के वातावरण में होना चाहिए, तो यह उन्हें पूंजी बनाने के लिए समझ में आता है। साइड नोट पर, बैश का मैनुअल वेरिएबल केस के लिए कन्वेंशन नहीं करता है। यहां तक कि यहाँ जवाब है "आमतौर पर" स्वीकार किए जाते हैं कहते हैं और केवल "मानक" गूगल, जो पूरे आईटी उद्योग का प्रतिनिधित्व नहीं करता द्वारा होता है।
सर्गी कोलोडियाज़नी

अन्य नोट पर @terdon, मैं 100% सहमत हूं कि लेख में चर का उल्लेख किया जाना चाहिए था, और यह ब्लॉग पर टिप्पणियों में भी बताया गया है। इसके अलावा, मैं किसी को कोडिंग की इस शैली का उपयोग करने के लिए न्याय नहीं करूंगा, भले ही वे किसी अन्य भाषा के लिए उपयोग किए जाएं या नहीं। यह पूरा प्रश्न और उत्तर स्पष्ट रूप से दिखाते हैं कि इसके फायदे हैं, और व्यक्ति की डिग्री जिसके लिए वे किसी अन्य भाषा में उपयोग किए जाते हैं, शायद यहाँ अप्रासंगिक है।
सर्गी कोलोडियाज़नी

1
@terdon अच्छी तरह से, लेख "स्रोत" सामग्री के हिस्से के रूप में पोस्ट किया गया था। मैं अपनी राय के रूप में सब कुछ पोस्ट कर सकता था, लेकिन मुझे बस यह श्रेय देना था कि कुछ सामान जो मैंने लेख से सीखा था, और यह सब समय के साथ शोध से आया है। लेखक के लिंक्डइन पेज से पता चलता है कि उनके पास सामान्य रूप से लिनक्स और आईटी के साथ अच्छा अनुभव है, इसलिए मुझे लगता है कि लेख वास्तव में ऐसा नहीं दिखाएगा, लेकिन मुझे आपके अनुभव पर भरोसा है जब यह लिनक्स और शेल स्क्रिप्टिंग की बात आती है, तो आप सही हो सकते हैं ।
सर्गी कोलोडियाज़नी

1
यह एक उत्कृष्ट उत्तर है, लेकिन मैं बैश में वैरिएबल गुंजाइश को जोड़ना चाहूंगा। इस कारण से, मैं फ़ंक्शन के localमाध्यम से सब कुछ का उपयोग करके और कॉल करने के लिए अपने चरों के अंदर अपने चरों को घोषित करना पसंद करता हूं main()। यह चीजों को बहुत अधिक प्रबंधनीय बनाता है और आप संभावित रूप से गड़बड़ स्थिति से बच सकते हैं।
गृहनी

65

पठनीयता एक बात है। लेकिन सिर्फ इस से अधिक modularisation है। ( अर्ध-मॉड्युलराइजेशन शायद कार्यों के लिए अधिक सही है।)

फ़ंक्शंस में आप कुछ वैरिएबल लोकल रख सकते हैं, जिससे विश्वसनीयता बढ़ती है , चीज़ों के गड़बड़ होने की संभावना कम होती है।

फ़ंक्शंस की एक और समर्थक पुन: प्रयोज्य है । एक बार किसी फ़ंक्शन को कोड करने के बाद, इसे स्क्रिप्ट में कई बार लागू किया जा सकता है। आप इसे दूसरी स्क्रिप्ट में भी पोर्ट कर सकते हैं।

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

जोड़ने के लिए एक और बिंदु। नीचे टिप्पणी में Etsitpab Nioliv नोटिस के रूप में, यह एक सुसंगत इकाई के रूप में कार्यों से पुनर्निर्देशित करना आसान है। लेकिन कार्यों के साथ पुनर्निर्देशन का एक और पहलू है। अर्थात्, पुनर्निर्देशन को फ़ंक्शन परिभाषा के साथ सेट किया जा सकता है। उदाहरण के लिए .:

f () { echo something; } > log

अब फ़ंक्शन कॉल द्वारा किसी भी स्पष्ट पुनर्निर्देशन की आवश्यकता नहीं है।

$ f

यह कई पुनरावृत्तियों को छोड़ सकता है, जो फिर से विश्वसनीयता बढ़ाता है और चीजों को क्रम में रखने में मदद करता है।

यह सभी देखें


55
बहुत अच्छा जवाब हालांकि यह बहुत बेहतर होगा अगर इसे कार्यों में तोड़ दिया गया।
बजे पियरे अरलाउड

1
हो सकता है कि उन कार्यों को जोड़ने से आप उस स्क्रिप्ट को किसी अन्य स्क्रिप्ट में आयात कर सकते हैं ( sourceया उपयोग करके . scriptname.sh, और उन कार्यों का उपयोग कर सकते हैं जैसे कि वे आपकी नई स्क्रिप्ट में थे।
स्नेकॉक

यह पहले से ही एक और उत्तर में शामिल है।
टॉमसज़

1
मैं सराहना करता हूँ। लेकिन मैं बल्कि अन्य लोगों को भी महत्वपूर्ण होने देना चाहूंगा।
टोमाज़

7
मुझे आज एक ऐसे मामले का सामना करना पड़ा जहाँ मुझे स्क्रिप्ट के कुछ आउटपुट को एक फ़ाइल में (ईमेल के माध्यम से भेजने के लिए) गूँजने के बजाय पुनर्निर्देशित करना पड़ा। मुझे बस वांछित कार्यों के उत्पादन को पुनर्निर्देशित करने के लिए myFunction >> myFile करना था। बहुत सुविधाजनक है। प्रासंगिक हो सकता है।
ईत्सितपब नाइलिव

39

अपनी टिप्पणी में, मैंने कार्यों के तीन लाभों का उल्लेख किया है:

  1. वे शुद्धता का परीक्षण और सत्यापन करना अधिक आसान हैं।

  2. भविष्य की लिपियों में कार्यों का आसानी से पुन: उपयोग (खट्टा) किया जा सकता है

  3. आपके बॉस उन्हें पसंद करते हैं।

और, नंबर 3 के महत्व को कभी कम मत समझो।

मैं एक और मुद्दे को संबोधित करना चाहूंगा:

... इसलिए रन ऑर्डर को मनमाने ढंग से स्वैप करने में सक्षम होना कुछ ऐसा नहीं है जो हम आम तौर पर कर रहे हैं। उदाहरण के लिए, यदि आप अचानक डाल करने के लिए नहीं चाहते हैं declare_variablesके बाद walk_into_bar, कि चीजें टूट जाएगा।

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

आदर्श रूप से, कार्यों को व्यक्तिगत रूप से परीक्षण करना आसान होना चाहिए। यदि, बातचीत के कारण, वे परीक्षण करना आसान नहीं हैं, तो यह एक संकेत है कि वे रिफैक्टरिंग से लाभ उठा सकते हैं।


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

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

@Xalorous मैंने ऐसी प्रथाओं को देखा है जहां वैश्विक चर एक प्रक्रिया में प्रारंभ होते हैं , एक मध्यवर्ती और त्वरित कदम के रूप में एक प्रक्रिया के विकास से पहले एक बाहरी फ़ाइल से उनके मूल्य को पढ़ता है ... मैं मानता हूं कि इसे अलग परिभाषा के लिए क्लीनर होना चाहिए और आरंभीकरण लेकिन शायद ही कभी आपको लाभ संख्या 3 से गुजरना ;-)
पड़े

13

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

हालाँकि, आपके कोड को देखते हुए, मुझे चर घोषित करने के लिए एक समारोह होना काफी अजीब लगता है; यह वास्तव में मुझे एक आँख भौंह उठता है।


अनिर्धारित उत्तर IMHO। क्या आप mainफ़ंक्शन / विधि में चर घोषित करने का सुझाव देते हैं , फिर?
डेविड टैबरेरो एम।

12

जबकि मैं पूरी तरह से सहमत पुनर्प्रयोग , पठनीयता , और नाजुक मालिकों चुंबन लेकिन वहाँ में कार्यों में से एक अन्य लाभ यह है : चर गुंजाइश । के रूप में एलडीपी शो :

#!/bin/bash
# ex62.sh: Global and local variables inside a function.

func ()
{
  local loc_var=23       # Declared as local variable.
  echo                   # Uses the 'local' builtin.
  echo "\"loc_var\" in function = $loc_var"
  global_var=999         # Not declared as local.
                         # Therefore, defaults to global. 
  echo "\"global_var\" in function = $global_var"
}  

func

# Now, to see if local variable "loc_var" exists outside the function.

echo
echo "\"loc_var\" outside function = $loc_var"
                                      # $loc_var outside function = 
                                      # No, $loc_var not visible globally.
echo "\"global_var\" outside function = $global_var"
                                      # $global_var outside function = 999
                                      # $global_var is visible globally.
echo                      

exit 0
#  In contrast to C, a Bash variable declared inside a function
#+ is local ONLY if declared as such.

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

पुन: प्रयोज्यता का अर्थ अक्सर कार्यों का एक सामान्य पुस्तकालय बनाना होता है और sourceउस पुस्तकालय को आपकी सभी लिपियों में सम्मिलित करना होता है । यह उन्हें तेज़ी से चलाने में मदद नहीं करेगा, लेकिन यह आपको उन्हें तेज़ी से लिखने में मदद करेगा।


कुछ लोग स्पष्ट रूप से उपयोग कर रहे हैं local, लेकिन मुझे लगता है कि अधिकांश लोग स्क्रिप्ट लिखते हैं जो फ़ंक्शन में टूट जाते हैं फिर भी डिजाइन सिद्धांत का पालन करते हैं। Usign localबस बगों को पेश करना कठिन बनाता है।
वू

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

10

पहले से ही अन्य उत्तरों में दिए गए उन लोगों से पूरी तरह से अलग कारण: एक कारण यह तकनीक कभी-कभी उपयोग की जाती है, जहां शीर्ष स्तर पर एकमात्र गैर-फ़ंक्शन-परिभाषा कथन एक कॉल है main, यह सुनिश्चित करने के लिए है कि स्क्रिप्ट गलती से कुछ बुरा नहीं करती है यदि स्क्रिप्ट को काट दिया जाता है। यदि स्क्रिप्ट को A से प्रोसेस B (शेल) तक पाइप किया गया है, तो स्क्रिप्ट को छोटा किया जा सकता है, और पूरी स्क्रिप्ट लिखने से पहले A जिस भी कारण से समाप्त होता है, उस प्रक्रिया को समाप्त करता है। यदि प्रक्रिया A दूरस्थ संसाधन से स्क्रिप्ट लाती है, तो यह विशेष रूप से होने की संभावना है। जबकि सुरक्षा कारणों से यह एक अच्छा विचार नहीं है, यह कुछ ऐसा है जो किया जाता है, और समस्या को दूर करने के लिए कुछ लिपियों को संशोधित किया गया है।


5
दिलचस्प! लेकिन मुझे यह परेशान करता है कि प्रत्येक कार्यक्रम में उन चीजों का ध्यान रखना पड़ता है। दूसरी ओर, ठीक यही main()पैटर्न सामान्य रूप से पायथन में है जहां कोई if __name__ == '__main__': main()फ़ाइल के अंत में उपयोग करता है ।
मार्टिन उडिंग

1
पायथन मुहावरे का फायदा है कि अन्य स्क्रिप्ट importको बिना स्क्रिप्ट के चलन से बाहर कर दिया जाता है main। मुझे लगता है कि एक समान गार्ड को बैश स्क्रिप्ट में रखा जा सकता है।
जेक कॉब

@ जेक कॉब हां। मैं अब सभी नई बैश लिपियों में ऐसा करता हूं। मेरे पास एक स्क्रिप्ट है जिसमें सभी नई लिपियों द्वारा उपयोग किए जाने वाले कार्यों का एक बुनियादी ढांचा है। उस स्क्रिप्ट को खट्टा या निष्पादित किया जा सकता है। यदि खटास आती है, तो इसका मुख्य कार्य निष्पादित नहीं किया जाता है। स्रोत बनाम निष्पादन का पता लगाना इस तथ्य से है कि BASH_SOURCE में निष्पादन स्क्रिप्ट का नाम शामिल है। यदि यह कोर स्क्रिप्ट के समान है, तो स्क्रिप्ट निष्पादित हो रही है। नहीं तो खट्टा हो रहा है।
डोकलावगर

7

एक प्रक्रिया के लिए एक अनुक्रम की आवश्यकता होती है। अधिकांश कार्य अनुक्रमिक हैं। यह आदेश के साथ खिलवाड़ करने के लिए कोई मतलब नहीं है।

लेकिन प्रोग्रामिंग के बारे में सुपर बड़ी बात - जिसमें स्क्रिप्टिंग शामिल है - परीक्षण है। परीक्षण, परीक्षण, परीक्षण। वर्तमान में आपको अपनी लिपियों की शुद्धता को प्रमाणित करने के लिए कौन सी परीक्षण लिपियाँ हैं?

आपका बॉस आपको स्क्रिप्ट किड होने से लेकर प्रोग्रामर बनने तक का मार्गदर्शन करने की कोशिश कर रहा है। अंदर जाने के लिए यह एक अच्छी दिशा है। आपके बाद आने वाले लोग आपको पसंद करेंगे।

परंतु। हमेशा अपनी प्रक्रिया उन्मुख जड़ों को याद रखें। यदि यह समझ में आता है कि जिस क्रम में उन्हें आम तौर पर निष्पादित किया जाता है, उस क्रम में दिए गए फ़ंक्शंस हैं, तो कम से कम पहले पास के रूप में ऐसा करें।

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

बाद में फिर भी, आपको एहसास हो सकता है कि आपने अब छोटे सहायक कार्यों के पुस्तकालयों को लिखा है जो आप अपनी कई लिपियों में उपयोग करते हैं।


6

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

विचार करें कि क्या मैंने आपको इस तरह के निर्देश दिए हैं:

Place your hands on your desk.
Tense your arm muscles.
Extend your knee and hip joints.
Relax your arms.
Move your arms backwards.
Move your left leg backwards.
Move your right leg backwards.
(continue for 10,000 more lines)

जब तक आप आधे रास्ते से, या यहाँ तक कि 5% तक पहुँच गए, तब तक आप भूल गए होंगे कि पहले कई कदम क्या थे। आप संभवतः अधिकांश समस्याओं का समाधान नहीं कर सकते, क्योंकि आप पेड़ों के लिए जंगल नहीं देख सकते थे। कार्यों के साथ तुलना करें:

stand_up();
walk_to(break_room);
pour(coffee);
walk_to(office);

यह निश्चित रूप से बहुत अधिक समझने योग्य है, चाहे आप लाइन-बाय-लाइन अनुक्रमिक संस्करण में कितनी भी टिप्पणियां डाल सकते हैं। यह भी बनाता है अब तक अधिक होने की संभावना आप ध्यान देंगे कि आप भूल कर कॉफी, और शायद () sit_down भूल अंत में। जब आपका मन grep और awk regexes के विवरण के बारे में सोच रहा है, तो आप बड़ी तस्वीर नहीं सोच सकते - "अगर कोई कॉफी नहीं बनी है तो क्या होगा"?

फ़ंक्शंस मुख्य रूप से आपको बड़ी तस्वीर देखने की अनुमति देते हैं, और ध्यान दें कि आप कॉफ़ी बनाना भूल गए (या कि कोई चाय पसंद कर सकता है)। एक और समय में, मन के एक अलग फ्रेम में, आप विस्तृत कार्यान्वयन के बारे में चिंता करते हैं।

निश्चित रूप से अन्य उत्तरों में चर्चा किए गए अन्य लाभ भी हैं। अन्य उत्तरों में स्पष्ट रूप से कहा गया एक और लाभ यह है कि फ़ंक्शन एक गारंटी प्रदान करता है जो बग को रोकने और ठीक करने में महत्वपूर्ण है। यदि आपको पता चलता है कि उचित फ़ंक्शन walk_to () में कुछ चर $ foo गलत थे, तो आप जानते हैं कि आपको केवल उस समस्या की अन्य 6 पंक्तियों को देखना होगा, जो उस समस्या से प्रभावित हो सकती है, और जो कुछ भी हो सकता है, उसे खोजने के लिए। गलत होने का कारण बना। बिना (उचित) कार्यों के, पूरे सिस्टम में कुछ भी और सब कुछ $ foo के गलत होने का कारण हो सकता है, और कुछ भी और सब कुछ $ foo से प्रभावित हो सकता है। इसलिए आप कार्यक्रम की हर एक पंक्ति की पुन: जांच किए बिना $ foo को सुरक्षित रूप से ठीक नहीं कर सकते। यदि $ फू एक समारोह के लिए स्थानीय है,


1
यह bashवाक्य रचना नहीं है। हालांकि यह शर्म की बात है; मुझे नहीं लगता कि इस तरह के कार्यों के लिए इनपुट पास करने का एक तरीका है। (यानी pour();< coffee)। यह अधिक लगता है c++या php(मुझे लगता है)।
आवाज

2
कोष्ठक के बिना @ tjt263, यह बैश वाक्य रचना है: कॉफी डालना। Parens के साथ, यह बहुत ही हर दूसरी भाषा है। :)
रे मॉरिस

5

प्रोग्रामिंग के बारे में कुछ प्रासंगिक बातें:

  • आपका कार्यक्रम बदल जाएगा, भले ही आपका बॉस जोर देकर कहे कि यह मामला नहीं है।
  • केवल कोड और इनपुट प्रोग्राम के व्यवहार को प्रभावित करते हैं।
  • नामकरण मुश्किल है।

टिप्पणियाँ * कोड * में अपने विचारों को स्पष्ट रूप से व्यक्त करने में सक्षम नहीं होने के लिए एक स्टॉप-गैप के रूप में शुरू होती हैं, और परिवर्तन के साथ खराब (या बस गलत) हो जाती हैं। इसलिए, यदि संभव हो तो, अवधारणाओं, संरचनाओं, तर्क, शब्दार्थ, प्रवाह, त्रुटि से निपटने और कोड के रूप में कोड की समझ के अनुसार कुछ और व्यक्त करें

कहा कि, बैश कार्यों में कुछ मुद्दे हैं जो अधिकांश भाषाओं में नहीं मिलते हैं:

  • बाश में नामकरण भयानक है। उदाहरण के लिए, localवैश्विक नामस्थान को प्रदूषित करने में कीवर्ड परिणामों का उपयोग करना भूल जाते हैं ।
  • के बाहर निकलने के कोड को खोनेlocal foo="$(bar)" में परिणामों का उपयोग करना ।bar
  • कोई नामित पैरामीटर नहीं हैं, इसलिए आपको ध्यान रखना होगा कि "$@"विभिन्न संदर्भों में क्या मतलब है।

* मुझे खेद है कि अगर यह बंद हो जाता है, लेकिन कुछ वर्षों के लिए टिप्पणियों का उपयोग करने और उनके बिना विकसित होने के बाद ** अधिक वर्षों तक यह बहुत स्पष्ट है जो श्रेष्ठ है।

** लाइसेंस के लिए टिप्पणियों का उपयोग करना, एपीआई प्रलेखन और इस तरह अभी भी आवश्यक है।


मैं उन्हें घोषित समारोह की शुरुआत में शून्य पर ... द्वारा लगभग सभी स्थानीय चर सेट local foo=""तो परिणाम पर कार्रवाई करने के आदेश निष्पादन का उपयोग कर उन्हें स्थापित करने ... foo="$(bar)" || { echo "bar() failed"; return 1; }। जब आवश्यक मूल्य निर्धारित नहीं किया जा सकता है तो यह हमें जल्दी से कार्य से बाहर कर देता है। घुंघराले ब्रेसिज़ का बीमा करना आवश्यक है जो return 1केवल विफलता पर निष्पादित होता है।
DocSalvager 12

5

समय ही धन है

ऐसे अन्य अच्छे उत्तर हैं जो तकनीकी कारणों पर प्रकाश डालते हैं, एक पटकथा लिखने के लिए , संभवतः लंबे समय तक, एक कामकाजी माहौल में विकसित, व्यक्तियों के एक समूह द्वारा इस्तेमाल किया जा सकता है और न केवल आपके स्वयं के उपयोग के लिए।

मैं एक उम्मीद पर ध्यान केंद्रित करना चाहता हूं : काम के माहौल में "समय पैसा है" । इसलिए बग्स की अनुपस्थिति और आपके कोड के प्रदर्शन का मूल्यांकन पठनीयता , परीक्षणशीलता , स्थिरता , शोधन क्षमता, पुन : प्रयोज्य के साथ मिलकर किया जाता है ...

"मॉड्यूल" में लिखने से एक कोड की रीडिंग के समय में कमी आएगी, न केवल स्वयं कोडर द्वारा बल्कि परीक्षक द्वारा या बॉस द्वारा उपयोग किए जाने वाले समय में भी। इसके अलावा ध्यान दें कि एक बॉस का समय आमतौर पर अधिक भुगतान किया जाता है और एक कोडर का समय होता है और आपका बॉस आपकी नौकरी की गुणवत्ता का मूल्यांकन करेगा।

इसके अलावा स्वतंत्र "मॉड्यूल" में एक कोड (यहां तक ​​कि एक बश स्क्रिप्ट) आपको अपनी टीम के अन्य घटक के साथ "समानांतर" में काम करने की अनुमति देगा, जिससे समग्र उत्पादन समय को छोटा किया जा सके और एक हिस्से की समीक्षा या पुन: लिखने के लिए सर्वश्रेष्ठ एकल विशेषज्ञता का उपयोग किया जा सके। दूसरों पर कोई साइड इफेक्ट नहीं, आपके द्वारा लिखे कोड को "जैसा है" को रीसायकल करनाएक अन्य कार्यक्रम / स्क्रिप्ट के लिए, पुस्तकालयों (या स्निपेट्स के पुस्तकालय) बनाने के लिए, समग्र आकार और त्रुटियों की संबंधित संभावना को कम करने के लिए, प्रत्येक एकल भाग को पूरी तरह से डिबग और टेस्ट करने के लिए ... और निश्चित रूप से यह आपके प्रोग्राम को तार्किक अनुभाग में व्यवस्थित करेगा। / स्क्रिप्ट और इसकी पठनीयता में वृद्धि। सभी चीजें जो समय और इतने पैसे बचाएंगी। दोष यह है कि आपको मानकों से चिपकना होगा और अपने कार्यों पर टिप्पणी करनी होगी (जो कि आपके पास काम करने के माहौल में नहीं है)।

एक मानक का पालन करने के लिए शुरुआत में आपका काम धीमा हो जाएगा, लेकिन यह बाद में अन्य सभी (और आपके भी) के काम को गति देगा। वास्तव में जब सहयोग में शामिल लोगों की संख्या बढ़ती है तो यह एक अपरिहार्य आवश्यकता बन जाती है। तो, उदाहरण के लिए, भले ही मुझे विश्वास है कि वैश्विक चर में परिभाषित किया जा करने के लिए है विश्व स्तर पर एक समारोह में और नहीं, मैं एक मानक है कि उन्हें नाम के एक समारोह में inizializes समझ सकता हूँ declare_variables()की पहली पंक्ति में हमेशा कहा जाता है main()एक ...

अंतिम लेकिन कम से कम, आधुनिक स्रोत कोड संपादकों को दिखाने या चुनिंदा अलग-अलग दिनचर्या ( कोड तह ) को छिपाने की संभावना को कम मत समझो । यह कोड को कॉम्पैक्ट रखेगा और उपयोगकर्ता की बचत को फिर से समय पर केंद्रित करेगा।

यहाँ छवि विवरण दर्ज करें

यहां ऊपर आप देख सकते हैं कि यह केवल फ़ंक्शन कैसे प्रकटwalk_into_bar() होता है। यहां तक ​​कि अन्य की भी 1000 लाइनें लंबी थीं, फिर भी आप किसी एक पृष्ठ के सभी कोड को नियंत्रित कर सकते हैं। ध्यान दें कि यह वह खंड भी है जहाँ आप चरों को घोषित / आरंभ करने के लिए जाते हैं।


1

अन्य उत्तरों में दिए गए कारणों के अलावा:

  1. मनोविज्ञान: एक प्रोग्रामर जिसकी उत्पादकता कोड की लाइनों में मापी जा रही है, को अनावश्यक रूप से क्रिया कोड लिखने के लिए एक प्रोत्साहन मिलेगा। अधिक प्रबंधन कोड की तर्ज पर ध्यान केंद्रित कर रहा है, प्रोग्रामर को अपने कोड को अनावश्यक जटिलता के साथ विस्तारित करने के लिए अधिक प्रोत्साहन देना होगा। यह अवांछनीय है क्योंकि बढ़ी हुई जटिलता रखरखाव की बढ़ती लागत और बग फिक्सिंग के लिए आवश्यक प्रयास में वृद्धि कर सकती है।

यह इतना बुरा जवाब नहीं है, जैसा कि डाउनवोट्स कहते हैं। नोट: agc कहता है, यह भी एक संभावना है, और हाँ, यह है। वह यह नहीं कहता कि यह एकमात्र संभावना होगी, और किसी पर आरोप नहीं लगाता, केवल तथ्यों को बताता है। हालांकि मुझे लगता है कि आज लगभग प्रत्यक्ष "कोड लाइन" -> "$ $" शैली अनुबंध की नौकरी है, अप्रत्यक्ष मतलब है कि यह काफी सामान्य है, हाँ, उत्पादित कोड का द्रव्यमान नेताओं / मालिकों द्वारा गिना जाता है।
user259412

0

एक और कारण जिसे अक्सर अनदेखा किया जाता है वह है बैश के वाक्य विन्यास को पार्स करना:

set -eu

echo "this shouldn't run"
{
echo "this shouldn't run either"

इस लिपि में स्पष्ट रूप से एक सिंटैक्स त्रुटि है और बैश बिल्कुल नहीं चलना चाहिए, है ना? गलत।

~ $ bash t1.sh
this shouldn't run
t1.sh: line 7: syntax error: unexpected end of file

यदि हम किसी फ़ंक्शन में कोड को लपेटते हैं, तो ऐसा नहीं होगा:

set -eu

main() {
  echo "this shouldn't run"
  {
  echo "this shouldn't run either"
}

main
~ $ bash t1.sh
t1.sh: line 10: syntax error: unexpected end of file
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.