बहुत अधिक शेबंग (स्क्रिप्ट घोषणा) लाइनें - किसी भी तरह से अपनी राशि को कम करने के लिए?


12

मेरे पास एक परियोजना है जिसमें लगभग 20 छोटी .shफाइलें शामिल हैं। मैं इन "छोटे" का नाम देता हूं क्योंकि आम तौर पर, किसी भी फ़ाइल में कोड की 20 से अधिक लाइनें नहीं होती हैं। मैंने एक मॉड्यूलर दृष्टिकोण लिया क्योंकि इस प्रकार मैं यूनिक्स दर्शन के लिए वफादार हूं और परियोजना को बनाए रखना मेरे लिए आसान है।

प्रत्येक .shफ़ाइल की शुरुआत में , मैंने डाला #!/bin/bash

सीधे शब्दों में, मुझे समझ में आया कि स्क्रिप्ट घोषणाओं के दो उद्देश्य हैं:

  1. वे उपयोगकर्ता को यह याद रखने में मदद करते हैं कि फ़ाइल को निष्पादित करने के लिए किस शेल की आवश्यकता है (जैसे, फ़ाइल का उपयोग किए बिना कुछ वर्षों के बाद)।
  2. वे यह सुनिश्चित करते हैं कि स्क्रिप्ट केवल एक निश्चित शेल (उस मामले में बैश) के साथ चलती है, जब किसी अन्य शेल का उपयोग किया गया था तो अप्रत्याशित व्यवहार को रोकने के लिए।

जब कोई प्रोजेक्ट 5 फाइलों से 20 फाइलों तक या 20 फाइलों से 50 फाइलों तक बढ़ने लगता है (यह मामला नहीं है, लेकिन सिर्फ प्रदर्शित करने के लिए) हमारे पास 20 लाइनें या स्क्रिप्ट घोषणाओं की 50 लाइनें हैं । मैं मानता हूं, भले ही यह कुछ के लिए मज़ेदार हो, लेकिन यह मेरे लिए 20 या 50 का उपयोग करने के लिए थोड़ा बेमानी लगता है, बजाय केवल 1 प्रति प्रोजेक्ट (शायद परियोजना की मुख्य फ़ाइल में) कहें ।

क्या 20 या 50 के इस कथित अतिरेक से बचने का एक तरीका है या कुछ मुख्य फ़ाइल में "वैश्विक" स्क्रिप्ट घोषणा का उपयोग करके स्क्रिप्ट घोषणाओं की अधिक से अधिक संख्या है?


2
आपको नहीं करना चाहिए था लेकिन; इसे हटाने और के साथ अपने सभी आलेख निष्पादित/bin/bash -x "$script"
jesse_b


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

जवाबों:


19

भले ही आपकी परियोजना अब पूरी तरह से 50 बैश लिपियों से युक्त हो सकती है, लेकिन यह जल्द ही या बाद में अन्य भाषाओं में लिखी गई लिपियों को जमा करना शुरू कर देगी, जैसे पर्ल या पायथन (इन स्क्रिप्टिंग भाषाओं के लाभों के लिए जो बैश के पास नहीं हैं)।

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

शेल लिपियों को बिना #!इनलाइन किए और बिना किसी स्पष्ट व्याख्याकार के अलग-अलग तरीकों से निष्पादित किया जाता है, जो इस बात पर निर्भर करता है कि शेल उन्हें किस रूप में आमंत्रित करता है (देखें उदाहरण के लिए कि कौन सा शेल इंटरप्रेटर स्क्रिप्ट को बिना शेबंग और विशेष रूप से स्टीफन के उत्तर के साथ चलाता है ), जो आप नहीं चाहते हैं? एक उत्पादन वातावरण में (आप लगातार व्यवहार चाहते हैं, और संभवतः पोर्टेबिलिटी भी)।

एक स्पष्ट दुभाषिया के साथ निष्पादित लिपियों को उस दुभाषिया द्वारा चलाया जाएगा, चाहे जो भी #!-लाइन कहे। यदि आप पुन: लागू करने का निर्णय लेते हैं, तो यह कहेंगे कि आप पायथन या किसी अन्य भाषा में एक बैश स्क्रिप्ट का उपयोग करेंगे।

आपको उन अतिरिक्त कीस्ट्रोक्स को खर्च करना चाहिए और हमेशा #!प्रत्येक स्क्रिप्ट के लिए एक- इनलाइन जोड़ना चाहिए ।


कुछ वातावरणों में, प्रत्येक प्रोजेक्ट में प्रत्येक स्क्रिप्ट में बहु-पैरा बॉयलरप्लेट कानूनी ग्रंथ होते हैं। बहुत खुश #!होइए कि यह केवल एक इनलाइन है जो आपके प्रोजेक्ट में "बेमानी" लगता है।


इस द्वारा उत्तर का विस्तार किया जाना चाहिए: शेल #!लाइन द्वारा दुभाषिया को निर्धारित करता है जैसे ही फ़ाइल में अनुमति की अनुमति होती है और एक दुभाषिया द्वारा लोड नहीं किया जाता है, लेकिन शेल द्वारा। /path/to/myprog.plयदि #!लाइन मौजूद है (पर्ल इंटरप्रेटर की ओर इशारा करते हुए) और फाइल ने अनुमति दी है, तो एक पर्ल प्रोग्राम चलाता है ।
14

11

आप की बात को गलत समझा #!। यह वास्तव में परिभाषित दुभाषिया के तहत इस कार्यक्रम को चलाने के लिए ऑपरेटिंग सिस्टम का एक निर्देश है।

तो एक स्क्रिप्ट हो सकती है #!/usr/bin/perlऔर परिणामी कार्यक्रम के रूप में चलाया जा सकता है ./myprogramऔर पर्ल दुभाषिया का उपयोग किया जा सकता है। इसी तरह #!/usr/bin/pythonएक कार्यक्रम अजगर के तहत चलाने का कारण होगा।

तो लाइन #!/bin/bashओएस को इस प्रोग्राम को बैश के तहत चलाने के लिए कहती है।

यहाँ एक उदाहरण है:

$ echo $0
/bin/ksh

$ cat x
#!/bin/bash

ps -aux | grep $$

$ ./x
sweh      2148  0.0  0.0   9516  1112 pts/5    S+   07:58   0:00 /bin/bash ./x
sweh      2150  0.0  0.0   9048   668 pts/5    S+   07:58   0:00 grep 2148

इसलिए, मेरे शेल के ksh होने के बावजूद, प्रोग्राम "x" #!लाइन के कारण बैश के नीचे चलता है , और हम इसे प्रक्रिया सूची में स्पष्ट रूप से देख सकते हैं।


ps -auxचेतावनी दे सकते हैं,
Weijun झोउ

@WeijunZhou अधिक कहते हैं ...
Kusalananda

कुछ संस्करण psचेतावनी देता है Warning: bad syntax, perhaps a bogus '-'?
वीजुन झोउ

2
psदोनों suooprts बीएसडी और UXIX तर्क वाक्य रचना। -auxगलत है UNIX स्टीफन शायद इसका मतलब है auxजो सही है BSD
जैसन

1
लोग, 2 चीजें; (1) उदाहरण अवधारणा पर ध्यान केंद्रित करें (जो कि psकॉलिंग दिखाता है bash) स्पष्ट वाक्यविन्यास नहीं; (2) ps -auxचेतावनियों के बिना CentOS 7 और डेबियन 9 पर पूरी तरह से काम करता है; वह cut'n'paste मेरी मशीन से बिल्कुल आउटपुट था; की पूरी चर्चा अगर- आवश्यक है या नहीं वर्तमान संस्करण नहीं, बल्कि लिनक्स के पुराने संस्करणों पर लागू होती है ।
स्टीफन हैरिस

9

पर .sh

क्या बुरा है .shफ़ाइल-नाम के अंत में है।

कल्पना कीजिए कि आप अजगर में से एक स्क्रिप्ट को फिर से लिखते हैं।

खैर अब आपको पहली लाइन बदलनी #!/usr/bin/python3है, यह इतना बुरा नहीं है, क्योंकि आपको फाइल में कोड की हर दूसरी लाइन को भी बदलना होगा। लेकिन अगर आप भी से फ़ाइल नाम बदलने के लिए prog.shकरने के लिए prog.py। और फिर आपको हर जगह अन्य लिपियों में ढूंढना होगा, और आपके सभी उपयोगकर्ता स्क्रिप्ट्स (जिन्हें आप भी नहीं जानते थे), और नई स्क्रिप्ट का उपयोग करने के लिए उन्हें बदल दें। sed -e 's/.sh/.py/g'उन लोगों के लिए मदद कर सकते हैं जिनके बारे में आप जानते हैं। लेकिन अब आपका पुनरीक्षण नियंत्रण उपकरण बहुत सारी असंबंधित फाइलों में बदलाव दिखा रहा है।

वैकल्पिक रूप से यह यूनिक्स तरीके से करना और कार्यक्रम का नाम progनहीं prog.sh

पर #!

यदि आपके पास सही है #!, और निष्पादित करने के लिए अनुमति / मोड सेट करें। फिर आपको दुभाषिया जानने की जरूरत नहीं है। कंप्यूटर इसे आपके लिए करेगा।

chmod +x prog #on gnu adds execute permission to prog.
./prog #runs the program.

नॉन ग्नू सिस्टम के लिए chmod(और अष्टक सीखें) मैनुअल पढ़ें, शायद इसे वैसे भी पढ़ें।


1
हम्म, एक्सटेंशन जरूरी खराब नहीं हैं, कम से कम वे अन्य उपयोगकर्ताओं के साथ संवाद करने में मदद करते हैं कि फाइल का प्रकार क्या है।
सर्गी कोलोडियाज़नी

@SergiyKolodyazhnyy लेकिन आपको भाषा जानने की आवश्यकता नहीं है, आपको इसे चलाने की आवश्यकता है। यहां तक ​​कि Microsoft एक्सटेंशन से दूर जाने की कोशिश कर रहा है (दुर्भाग्य से यह मेरी छिपाई कर रहे हैं)। हालाँकि मैं मानता हूँ कि वे एक अच्छा विचार हो सकते हैं: .imageचित्रों के लिए। .audioध्वनि आदि के लिए। इस प्रकार आपको बता रहा है कि यह कार्यान्वयन / एन्कोडिंग के बारे में नहीं है।
ctrl-alt-delor

1
@ ctrl-alt-delor यदि फ़ाइल को कॉल किया जाता है launch-missilesया delete-project-and-make-manager-pissedमैं "बस इसे चलाना नहीं चाहता" जब मैं केवल भाषा के बारे में उत्सुक था :)
Sergiy Kolodyazhnyy

2
यदि आप भाषा के लिए उत्सुक हैं तो fileकमांड का उपयोग करें । यह अधिकांश फ़ाइल प्रकारों को पहचानता है।
जस

2
मैं मानता हूं कि निष्पादन योग्य स्क्रिप्ट के लिए एक्सटेंशन खराब हैं, बिल्कुल दिए गए कारणों के लिए। मैं एक स्क्रिप्ट के लिए एक .sh एक्सटेंशन का उपयोग करता हूं जिसे किसी अन्य शेल स्क्रिप्ट (यानी एक गैर-निष्पादन योग्य स्क्रिप्ट) द्वारा sourced करने की आवश्यकता है - उस परिदृश्य में, प्रत्यय है महत्वपूर्ण / मान्य क्योंकि यह बताता है कि हम फ़ाइल का उपयोग कैसे कर सकते हैं।
लॉरेंस रेनशॉ

8

[द हैशबैंग लाइन्स] सुनिश्चित करें कि स्क्रिप्ट केवल एक निश्चित शेल (उस स्थिति में बैश) के साथ चलती है ताकि अनपेक्षित व्यवहार को रोका जा सके यदि किसी अन्य शेल का उपयोग किया गया था।

यह संभवतः इंगित करने के लायक है कि यह काफी गलत है। किसी भी तरह से हैशबैंग लाइन आपको फ़ाइल को गलत शेल / इंटरप्रेटर में डालने की कोशिश करने से नहीं रोकती है:

$ cat array.sh
#!/bin/bash
a=(a b c)
echo ${a[1]} $BASH_VERSION
$ dash array.sh
array.sh: 2: array.sh: Syntax error: "(" unexpected

(या इसी तरह awk -f array.shआदि के साथ )


लेकिन किसी भी मामले में, प्रतिरूपकता के लिए एक और तरीका फाइलों में शेल फ़ंक्शन, प्रति फ़ाइल एक फ़ंक्शन, यदि आपको पसंद है, और फिर sourceमुख्य कार्यक्रम से फ़ाइलों को परिभाषित करना होगा । इस तरह, आपको हैशबैंग की आवश्यकता नहीं होगी: उन्हें किसी भी अन्य टिप्पणी के रूप में माना जाएगा, और सब कुछ उसी शेल का उपयोग करके चलेगा। नकारात्मक पक्ष यह होगा कि आपको sourceफ़ंक्शंस के साथ फ़ाइलों की आवश्यकता होगी (उदाहरण के लिए for x in functions/*.src ; do source "$x" ; done), और वे सभी एक ही शेल का उपयोग करके चलेंगे, इसलिए आप सीधे उनमें से एक को पर्ल-कार्यान्वयन के साथ बदल नहीं सकते हैं।


बैश सरणियों के साथ उदाहरण के लिए +1। एकाधिक गोले या पोसिक्स को परिभाषित करने वाले कुछ से अपरिचित उपयोगकर्ता, मान सकते हैं कि एक खोल की कुछ विशेषताएं दूसरे में मौजूद हैं। कार्यों के लिए भी, यह प्रासंगिक हो सकता है: unix.stackexchange.com/q/313256/85039
Sergiy Kolodyazhnyy

4

क्या 20 या 50 के इस कथित अतिरेक से बचने का एक तरीका है या कुछ मुख्य फ़ाइल में "वैश्विक" स्क्रिप्ट घोषणा का उपयोग करके स्क्रिप्ट घोषणाओं की अधिक से अधिक संख्या है?

वहाँ है - इसे पोर्टेबिलिटी या POSIX अनुपालन कहा जाता है। हमेशा पोर्टेबल, शेल-न्यूट्रल तरीके से स्क्रिप्ट लिखने के लिए प्रयास करें, उन्हें केवल एक स्क्रिप्ट से उपयोग करें #!/bin/shया जब आप उपयोग करते हैं/bin/sh अंतःक्रियात्मक रूप से करते हैं (या बहुत कम से कम POSIX- अनुपालन शेल जैसे ksh)।

हालाँकि, पोर्टेबल स्क्रिप्ट आपको इससे नहीं बचाते:

  • गोले ( ilkkachu के उत्तर में से एक की सुविधाओं का उपयोग करने की आवश्यकता है एक उदाहरण है)
  • गोले की तुलना में अधिक उन्नत स्क्रिप्टिंग भाषाओं का उपयोग करने की आवश्यकता (पायथन और पर्ल)
  • PEBKAC त्रुटि: आपकी स्क्रिप्ट उपयोगकर्ता के हाथों में आती है। JDoe, जो आपकी स्क्रिप्ट चलाता है जैसा कि आपने इसे इरादा नहीं किया था, उदाहरण के लिए वे /bin/shस्क्रिप्ट को चलाते हैं csh

यदि मैं अपनी राय व्यक्त कर सकता हूं, तो "अतिरेक से बचना" को समाप्त #!करना गलत लक्ष्य है। लक्ष्य लगातार प्रदर्शन होना चाहिए और वास्तव में एक कामकाजी स्क्रिप्ट है जो काम करती है, और कोने के मामलों पर विचार करती है, कुछ सामान्य नियमों का पालन करती है जैसे कि न-पार्सिंग-एलएस या हमेशा-उद्धृत-चर-जब तक-आवश्यकता-शब्द-विभाजन

वे उपयोगकर्ता को यह याद रखने में मदद करते हैं कि फ़ाइल को निष्पादित करने के लिए किस शेल की आवश्यकता है (जैसे, फ़ाइल का उपयोग किए बिना कुछ वर्षों के बाद)।

वे वास्तव में उपयोगकर्ता के लिए नहीं हैं - वे उचित इंटरप्रेटर चलाने के लिए ऑपरेटिंग सिस्टम के लिए हैं। इस मामले में "उचित", का मतलब ओएस पाता है कि शेबंग में क्या है; यदि गलत शेल के लिए नीचे दिया गया कोड - यह लेखक की गलती है। उपयोगकर्ता की स्मृति के लिए, मुझे नहीं लगता कि Microsoft Word या Google Chrome जैसे कार्यक्रमों के "उपयोगकर्ता" को कभी यह जानने की आवश्यकता है कि भाषा कार्यक्रम किस भाषा में लिखे गए हैं; लेखकों की आवश्यकता हो सकती है।

फिर फिर से, लिपियों में लिखी गई स्क्रिप्ट्स को यह याद रखने की आवश्यकता हो सकती है कि आपने किस शेल का उपयोग किया था, क्योंकि पोर्टेबल स्क्रिप्ट किसी भी POSIX-compliant शेल में काम करना चाहिए।

वे यह सुनिश्चित करते हैं कि स्क्रिप्ट केवल एक निश्चित शेल (उस मामले में बैश) के साथ चलती है, जब किसी अन्य शेल का उपयोग किया गया था तो अप्रत्याशित व्यवहार को रोकने के लिए।

वे नहीं करते। क्या वास्तव में अप्रत्याशित व्यवहार को रोकता है पोर्टेबल स्क्रिप्ट लिख रहा है।


1

जिस कारण आपको लगाने की आवश्यकता है #!/bin/bashप्रत्येक स्क्रिप्ट के शीर्ष पर है कि आप इसे एक अलग प्रक्रिया के रूप में चला रहे हैं।

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

यदि आप #!लाइन को हटाना चाहते हैं , तो आपके विकल्प हैं:

  1. स्क्रिप्ट को सीधे निष्पादित करें (जैसा कि आप अभी कर रहे हैं), और आशा है कि डिफ़ॉल्ट दुभाषिया स्क्रिप्ट से मेल खाता है - आप शायद अधिकांश लिनक्स सिस्टम पर सुरक्षित हैं, लेकिन अन्य प्रणालियों के लिए पोर्टेबल नहीं हैं (जैसे सोलारिस), और इसे बदला जा सकता है कुछ भी (मैं इसे vimफ़ाइल पर चलाने के लिए भी सेट कर सकता हूँ !)।

  2. स्क्रिप्ट का उपयोग करके निष्पादित करें bash myscript.sh। यह ठीक काम करता है, लेकिन आपको स्क्रिप्ट को पथ निर्दिष्ट करना होगा, और यह गड़बड़ है।

  3. स्रोत का उपयोग करके स्क्रिप्ट . myscript.sh, जो स्क्रिप्ट को वर्तमान दुभाषिया प्रक्रिया के भीतर चलाता है (यानी उप-प्रक्रिया के रूप में नहीं)। लेकिन यह लगभग निश्चित रूप से आपकी लिपियों में संशोधन की आवश्यकता होगी, और उन्हें कम मॉड्यूलर / पुन: प्रयोज्य बनाता है।

2 और 3 के मामलों में, फ़ाइल को अनुमतियों को निष्पादित करने की आवश्यकता नहीं है (और नहीं होनी चाहिए), और इसे .sh(या .bash) प्रत्यय देना एक अच्छा विचार है।

लेकिन उन विकल्पों में से कोई भी आपकी परियोजना के लिए अच्छा नहीं लगता है, जैसा कि आपने कहा था कि आप अपनी स्क्रिप्ट को मॉड्यूलर रखना चाहते हैं (=> स्वतंत्र और आत्म-निहित), इसलिए आपको अपनी #!/bin/bashलाइन को स्क्रिप्ट के शीर्ष पर रखना चाहिए ।

अपने प्रश्न में, आपने यह भी कहा कि आप यूनिक्स दर्शन का अनुसरण कर रहे हैं। यदि यह सच है, तो आपको सीखना चाहिए कि #!लाइन वास्तव में किस लिए है, और हर निष्पादन योग्य स्क्रिप्ट में इसका उपयोग करते रहें!


अच्छे उत्तर के लिए धन्यवाद। मैं जवाब में सब कुछ प्यार करता था और इस तक upvoting के बारे में सोचा then you should learn what the #! line is really for, and keep using it in every executable script!:। एक यू। फिलोसोफी का पालन कर सकते हैं ओ निश्चित रूप से ज्ञान की बात है। इन सभी उत्तरों के बाद मुझे समझ में आया कि क्यों इसे उस शब्द में शामिल किया जा सकता है। मैं उत्तर को संपादित करने का सुझाव देता हूं, इसे "यूनाईट फिलॉसफी के एक आंतरिक भाग के रूप में शेबंग देखें जिसे आप सम्मान करते हैं और अपनाते हैं"।
user9303970

1
क्षमा करें यदि मैं प्रत्यक्ष था, या यदि वह टिप्पणी असभ्य लगती थी। आपकी टिप्पणियों ने सुझाव दिया कि आप एक IDE में काम करना पसंद करते हैं - एक 'प्रोजेक्ट' के साथ जो आपको उस प्रोजेक्ट के भीतर स्क्रिप्ट के लिए वैश्विक नियमों को परिभाषित करने की अनुमति देता है। यह विकसित करने का एक वैध तरीका है, लेकिन यह प्रत्येक स्क्रिप्ट को एक स्वतंत्र, स्टैंडअलोन प्रोग्राम (यूनिक्स दर्शन जिसे आपने संदर्भित किया है) के रूप में व्यवहार करने के साथ अच्छी तरह से फिट नहीं है।
लॉरेंस रेनशॉ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.