में bash
या sh
, मैं कुछ भी जो साथ शुरू होता है लगता है कि #
एक है टिप्पणी ।
लेकिन bash
लिपियों में हम लिखते हैं:
#!/bin/bash
और पायथन लिपियों में:
#!/bin/python
क्या इसका मतलब यह है कि #
अपने आप में एक टिप्पणी है जबकि #!
नहीं है?
में bash
या sh
, मैं कुछ भी जो साथ शुरू होता है लगता है कि #
एक है टिप्पणी ।
लेकिन bash
लिपियों में हम लिखते हैं:
#!/bin/bash
और पायथन लिपियों में:
#!/bin/python
क्या इसका मतलब यह है कि #
अपने आप में एक टिप्पणी है जबकि #!
नहीं है?
जवाबों:
#!
लाइन प्रयोग किया जाता है से पहले स्क्रिप्ट चलाने है, तो ध्यान नहीं दिया जब स्क्रिप्ट चलाता है।आप पूछ रहे हैं कि एक शेबंग लाइन और एक साधारण टिप्पणी के बीच क्या अंतर है ।
के साथ शुरू होने वाली एक लाइन #!
बस किसी भी अन्य लाइन के रूप में एक टिप्पणी है जो इसके साथ शुरू होती है #
। यह सच है अगर #!
फ़ाइल की पहली पंक्ति है, या कहीं और। #!/bin/sh
एक प्रभाव है , लेकिन यह दुभाषिया द्वारा ही नहीं पढ़ा जाता है ।
#
सभी प्रोग्रामिंग भाषाओं में एक टिप्पणी नहीं है लेकिन, जैसा कि आप जानते हैं, यह बॉर्न-शैली के गोले में एक टिप्पणी है, sh
और bash
(साथ ही अधिकांश गैर-बॉर्न-शैली के गोले, जैसे csh
)। यह पायथन में एक टिप्पणी भी है । और यह विभिन्न प्रकार की कॉन्फ़िगरेशन फ़ाइलों में एक टिप्पणी है जो वास्तव में स्क्रिप्ट नहीं हैं (जैसे /etc/fstab
)।
मान लीजिए कि एक शेल स्क्रिप्ट शुरू होती है #!/bin/sh
। यह एक टिप्पणी है, और दुभाषिया (खोल) #
चरित्र के बाद लाइन पर सब कुछ अनदेखा करता है ।
एक #!
पंक्ति का उद्देश्य दुभाषिया को जानकारी देना नहीं है। #!
लाइन का उद्देश्य ऑपरेटिंग सिस्टम (या जो भी प्रक्रिया दुभाषिया लॉन्च करता है) को दुभाषिया के रूप में उपयोग करने के लिए बताना है ।
यदि आप स्क्रिप्ट को एक निष्पादन योग्य फ़ाइल के रूप में आमंत्रित करते हैं, उदाहरण के लिए, ./script.sh
चलकर, सिस्टम पहली पंक्ति को यह देखने के लिए सुरक्षित करता है कि क्या शुरू होता है #!
, इसके बाद शून्य या अधिक रिक्त स्थान होता है, इसके बाद एक कमांड होता है। यदि ऐसा होता है, तो यह उस स्क्रिप्ट के नाम के साथ उस तर्क के रूप में चलता है। इस उदाहरण में, यह /bin/sh script.sh
(या, तकनीकी रूप से /bin/sh ./script.sh
) चलता है ।
यदि आप इंटरप्रेटर को स्पष्ट रूप से कॉल करके स्क्रिप्ट को लागू करते हैं, तो #!
लाइन को कभी भी परामर्श नहीं दिया जाता है। इसलिए, यदि आप चलाते हैं sh script.sh
, तो पहली पंक्ति का कोई प्रभाव नहीं है। यदि script2.sh
पहली पंक्ति है #!/usr/games/nibbles
, तो रनिंग sh script2.sh
स्क्रिप्ट को nibbles
(लेकिन ./script2.sh
) खोलने का प्रयास नहीं करेगा।
आप देखेंगे कि न तो मामले में स्क्रिप्ट का विस्तार होता है ( .sh
), यदि यह एक है, तो इसे कैसे चलाया जाता है। यूनिक्स जैसी प्रणाली में, यह आमतौर पर स्क्रिप्ट को चलाने के तरीके को प्रभावित नहीं करता है। कुछ अन्य प्रणालियों पर, विंडोज की तरह, #!
शेबबैंग लाइन को सिस्टम द्वारा पूरी तरह से अनदेखा किया जा सकता है, और एक्सटेंशन यह निर्धारित कर सकता है कि स्क्रिप्ट क्या चलती है। (इसका मतलब यह नहीं है कि आपको अपनी स्क्रिप्ट एक्सटेंशन देने की आवश्यकता है, लेकिन यह एक कारण है कि यदि आप ऐसा करते हैं, तो उन्हें सही होना चाहिए।)
#!
इस उद्देश्य को ठीक से पूरा करने के लिए चुना गया क्योंकि #
एक टिप्पणी शुरू होती है। #!
लाइन प्रणाली, नहीं दुभाषिया के लिए है, और यह दुभाषिया द्वारा नजरअंदाज कर दिया जाना चाहिए।
आपने (मूल रूप से) कहा था कि आप लिपियों के #!/bin/sh
लिए उपयोग करते bash
हैं। आपको केवल यह करना चाहिए कि यदि स्क्रिप्ट को किसी भी bash
एक्सटेंशन की sh
आवश्यकता नहीं है - स्क्रिप्ट चलाने में सक्षम होने की आवश्यकता है। sh
हमेशा के लिए एक सहिष्णु नहीं है bash
। अक्सर, दूरस्थ रूप से हाल ही में डेबियन और उबंटू सिस्टम सहित sh
, एक सहिष्णुता है dash
।
आपने यह भी कहा (अपने प्रश्न के पहले संस्करण में, संपादन से पहले) कि आप अपनी पायथन स्क्रिप्ट के साथ शुरू करते हैं #!/bin/sh read by the interpretor
। यदि आप का शाब्दिक अर्थ है, तो आपको निश्चित रूप से ऐसा करना बंद कर देना चाहिए। यदि hello.py
उस रेखा से शुरू होता है, तो ./hello.py
निष्पादन चल रहा है :
/bin/sh read by the interpretor hello.py
/bin/sh
एक स्क्रिप्ट को निष्पादित करने की कोशिश करेगा जिसे read
( by the interpretor hello.py
इसके तर्कों के साथ) कहा जाता है , read
(उम्मीद है) नहीं मिलेगी, और आपकी पायथन स्क्रिप्ट कभी पायथन दुभाषिया द्वारा नहीं देखी जाएगी।
यदि आप यह गलती कर रहे हैं, लेकिन मेरे द्वारा बताई जा रही समस्या नहीं है, तो आप संभवतः व्याख्याता (उदाहरण के लिए python hello.py
) को स्पष्ट रूप से निर्दिष्ट करके अपने पायथन परिमार्जन को लागू कर रहे हैं , जिससे पहली पंक्ति को अनदेखा किया जा सकता है। जब आप अपनी स्क्रिप्ट दूसरों को वितरित करते हैं, या उन्हें लंबे समय बाद उपयोग करते हैं, तो यह स्पष्ट नहीं हो सकता है कि उनके लिए काम करना आवश्यक है। अब उन्हें ठीक करना सबसे अच्छा है। या कम से कम पहली पंक्ति को पूरी तरह से हटा दें, ताकि जब वे ./
त्रुटि संदेश के साथ चलने में विफल हो जाएं तो समझ में आएगा।
पाइथन लिपियों के लिए, यदि आप जानते हैं कि पाइथन इंटरप्रेटर कहाँ है (या होने वाला है), तो आप #!
उसी तरह से लाइन लिख सकते हैं :
#!/usr/bin/python
या, यदि यह एक पायथन 3 स्क्रिप्ट है, तो आपको निर्दिष्ट करना चाहिए python3
, क्योंकि python
लगभग हमेशा पायथन 2 है :
#!/usr/bin/python3
हालाँकि, समस्या यह है कि जबकि /bin/sh
हमेशा मौजूद होना चाहिए, और /bin/bash
लगभग हमेशा bash
ओएस के साथ आने वाले सिस्टम पर मौजूद है , पायथन कई स्थानों पर मौजूद हो सकता है।
इसलिए, कई पायथन प्रोग्रामर इसके बजाय इसका उपयोग करते हैं:
#!/usr/bin/env python
(या #!/usr/bin/env python3
अजगर के लिए 3.)
यह स्क्रिप्ट को env
सही जगह पर भरोसा करने के बजाय "सही जगह" पर निर्भर करता python
है। यह एक अच्छी बात है, क्योंकि:
env
में लगभग हमेशा स्थित है /usr/bin
।python
को चलाना चाहिए वह वही है जो पहले दिखाई देता है PATH
। शुरू hello.py
के साथ #!/usr/bin/env python
मेकअप ./hello.py
रन /usr/bin/env python hello.py
है, जो है (लगभग) चल के बराबर python hello.py
।आपके द्वारा उपयोग नहीं किया जा सकने वाला कारण #!python
यह है:
/
) द्वारा दिया गया इंटरप्रेटर निर्दिष्ट किया जाए ।python
वर्तमान निर्देशिका में कॉलिंग प्रक्रिया निष्पादित होगी । जब कमांड में स्लैश नहीं होता है तो पथ खोजना विशिष्ट शेल व्यवहार है।कभी-कभी एक पायथन या अन्य स्क्रिप्ट जो शेल स्क्रिप्ट नहीं होती है, एक शेलबंग लाइन होगी #!/bin/sh ...
जहां ...
से शुरू करना कुछ अन्य कोड है। यह कभी-कभी सही होता है, क्योंकि बॉर्न-संगत शेल ( sh
) को तर्क देने के कुछ तरीके हैं जिससे इसे पायथन इंटरप्रेटर के रूप में लागू किया जा सकता है। (तर्कों में से एक में संभवतः शामिल होगा python
।) हालांकि, अधिकांश उद्देश्यों के लिए, #!/usr/bin/env python
सरल, अधिक सुरुचिपूर्ण, और जिस तरह से आप चाहते हैं, काम करने की अधिक संभावना है।
कई प्रोग्रामिंग और स्क्रिप्टिंग भाषाएं, और कुछ अन्य फ़ाइल प्रारूप, #
एक टिप्पणी के रूप में उपयोग करते हैं । उनमें से किसी के लिए, भाषा में एक फ़ाइल एक प्रोग्राम द्वारा चलाई जा सकती है जो प्रोग्राम को पहले लाइन पर निर्दिष्ट करके एक तर्क के रूप में लेती है #!
।
कुछ प्रोग्रामिंग भाषाओं में, #
आम तौर पर एक टिप्पणी नहीं है, लेकिन एक विशेष मामले के रूप में पहली पंक्ति को नजरअंदाज कर दिया जाता है अगर इसके साथ शुरू होता है #!
। यह #!
सिंटैक्स के उपयोग की सुविधा देता है, भले ही #
अन्यथा एक पंक्ति एक टिप्पणी नहीं करता है।
हालांकि यह कम सहज है, किसी भी फ़ाइल जिसका फ़ाइल प्रारूप एक पहली पंक्ति को समायोजित कर सकता है जिसके साथ #!
निष्पादन योग्य का पूरा रास्ता शुरू हो सकता है, जिसमें एक शबंग रेखा हो सकती है। यदि आप ऐसा करते हैं, और फ़ाइल निष्पादन योग्य चिह्नित है, तो आप इसे प्रोग्राम की तरह चला सकते हैं ... जिससे इसे दस्तावेज़ की तरह खोला जा सके।
कुछ एप्लिकेशन जानबूझकर इस व्यवहार का उपयोग करते हैं। उदाहरण के लिए, VMware में, .vmx
फाइलें वर्चुअल मशीनों को परिभाषित करती हैं। आप एक वर्चुअल मशीन को "रन" कर सकते हैं, क्योंकि यह एक स्क्रिप्ट थी क्योंकि ये फाइलें निष्पादन योग्य हैं और इनमें एक शेबंग लाइन है, जिससे उन्हें VMware उपयोगिता में खोला जा सकता है।
rm
फ़ाइलें निकालता है। यह एक स्क्रिप्टिंग भाषा नहीं है। हालाँकि, एक फ़ाइल जो शुरू होती है #!/bin/rm
और निष्पादन योग्य होती है, उसे चलाया जा सकता है, और जब आप इसे चलाते हैं, rm
तो इसे हटा दिया जाता है।
इसे अक्सर "फ़ाइल हटाए जाने" के रूप में परिकल्पित किया जाता है। लेकिन फ़ाइल वास्तव में बिल्कुल नहीं चल रही है। यह .vmx
फ़ाइलों के लिए ऊपर वर्णित स्थिति की तरह अधिक है ।
फिर भी, क्योंकि #!
लाइन एक साधारण कमांड (कमांड लाइन तर्क सहित) को चलाने की सुविधा देती है, आप इस तरह से कुछ स्क्रिप्टिंग कर सकते हैं। "स्क्रिप्ट" के एक सरल उदाहरण से अधिक परिष्कृत #!/bin/rm
, विचार करें:
#!/usr/bin/env tee -a
यह उपयोगकर्ता इनपुट को अंतःक्रियात्मक रूप से लेता है, इसे वापस उपयोगकर्ता लाइन-बाय-लाइन पर echoes करता है, और इसे "स्क्रिप्ट" फ़ाइल के अंत में जोड़ता है।
उपयोगी? बहुत नहीं। वैचारिक रूप से दिलचस्प है? पूरी तरह से! हाँ। (कुछ हद तक।)
लिपियों / कार्यक्रमों में एक साथ कई भाषाएं हैं , उदाहरण के लिए, OSes में हैशबैंग कार्यक्षमता को अनुकरण करने के लिए जो ऐसा नहीं था ।
(इन कार्यक्रमों को पॉलीग्लॉट कहा जाता है , लेकिन सॉफ्टवेयर विकास में पॉलीग्लॉट के अन्य अर्थ के साथ भ्रमित नहीं होना है , एक कार्यक्रम / परियोजना जहां विभिन्न भागों को विभिन्न भाषाओं में लिखा जाता है।)
Metacommands QBasic / QuickBasic, जो संकलक कोड पीढ़ी के लिए विकल्प (संकलित कोड के लिए) के लिए संकेत है, लेकिन टिप्पणियों के कुछ हिस्सों और इस तरह वास्तविक संकलन / व्याख्या के दौरान उपेक्षा थे।
-x
ध्वज क्या करता है?
-x
"छोड़ें [s] पहली पंक्ति ..." दूसरी पंक्ति को 1
इसके स्थान पर क्रमांकित किया जाता है 2
, 2
इसके बजाय तीसरी पंक्ति 3
, आदि। यही कारण है कि आपको उस ध्वज का उपयोग नहीं करना चाहिए। ;) -x
गैर-यूनिक्स-जैसे ओएस पर स्क्रिप्टिंग के लिए है जिसमें शेबंग जैसा सिंटैक्स होता है, जिसके साथ शुरुआत नहीं होती है #
(इस तरह पायथन टिप्पणी नहीं)।
perl script.pl
बनाम ./script.pl
) तो दुभाषिया होगा जैसे झंडे पार्स करने के लिए कुटिया लाइन पढ़ -w
। हालांकि इस सुविधा पर भरोसा करने की अनुशंसा नहीं की गई है।
एक शेबबैंग चरित्र अनुक्रम होता है जिसमें वर्ण संख्या चिह्न और विस्मयादिबोधक चिह्न (जैसे "#!") होता है, जब यह किसी स्क्रिप्ट की प्रारंभिक पंक्ति पर प्रारंभिक दो वर्णों के रूप में होता है।
* निक्स ऑपरेटिंग सिस्टम के तहत, जब एक स्क्रिप्ट एक शेबबैंग के साथ शुरू होती है, तो प्रोग्राम लोडर एक स्क्रिप्ट के प्रारंभिक लाइन के बाकी हिस्से को एक दुभाषिया निर्देश के रूप में पार्स करता है; इसके बजाय निर्दिष्ट दुभाषिया कार्यक्रम चलाया जाता है, इसे एक तर्क के रूप में पारित किया जाता है जो स्क्रिप्ट को चलाने का प्रयास करते समय शुरू में उपयोग किया जाता था। उदाहरण के लिए, यदि किसी स्क्रिप्ट का नाम "पथ / से / आपकी स्क्रिप्ट" रखा गया है, और यह निम्न पंक्ति से शुरू होती है:
#!/bin/sh
फिर प्रोग्राम लोडर को निर्देश दिया जाता है कि वह प्रोग्राम "/ बिन / श" के बजाय उदाहरण के लिए बोर्न शेल या एक संगत शेल, "तर्क / पथ / से / अपनी स्क्रिप्ट" को पहले तर्क के रूप में पारित करे।
तदनुसार, इसे "पथ / टू / पायथन-स्क्रिप्ट" पथ के साथ एक स्क्रिप्ट का नाम दिया गया है और यह निम्न पंक्ति से शुरू होता है:
#!/bin/python
फिर लोड किए गए प्रोग्राम को पहले तर्क के रूप में "पथ / / से / पायथन-लिपि" पास करते हुए, उदाहरण के लिए प्रोग्राम "/ बिन / पाइथन" चलाने का निर्देश दिया जाता है।
संक्षेप में "#" एक पंक्ति पर टिप्पणी करेगा जबकि चरित्र अनुक्रम "#!" एक स्क्रिप्ट की प्रारंभिक पंक्ति पर पहले दो पात्रों के रूप में होने का अर्थ उपरोक्त के रूप में है।
विवरण के लिए देखें कि कुछ स्क्रिप्ट # से क्यों शुरू होती हैं! ...?
स्रोत: इस उत्तर के कुछ वर्गों से (मामूली संशोधन के साथ) प्राप्त कर रहे हैं कुटिया (Unix) पर अंग्रेजी विकिपीडिया (द्वारा विकिपीडिया योगदानकर्ताओं )। यह आलेख CC-BY-SA 3.0 के तहत लाइसेंस प्राप्त है , जो AU पर उपयोगकर्ता सामग्री के समान है, इसलिए इस व्युत्पत्ति को रोपण के साथ अनुमति दी जाती है।
#!
shebang
इसे तब कहा जाता है जब यह किसी स्क्रिप्ट की प्रारंभिक लाइन पर शुरुआती दो अक्षरों के रूप में होता है। इसका उपयोग स्क्रिप्ट में निष्पादन के लिए दुभाषिया को इंगित करने के लिए किया जाता है। shebang
ऑपरेटिंग सिस्टम (गिरी), खोल के लिए नहीं करने के लिए है, तो यह एक टिप्पणी के रूप में व्याख्या नहीं की जाएगी।
सौजन्य: http://en.wikipedia.org/wiki/Shebang_%28Unix%29
सामान्य तौर पर, यदि कोई फ़ाइल निष्पादन योग्य है, लेकिन वास्तव में निष्पादन योग्य (बाइनरी) प्रोग्राम नहीं है, और ऐसी कोई रेखा मौजूद है, तो प्रोग्राम # के लिए निर्दिष्ट है! स्क्रिप्टनेम और उसके सभी तर्कों के साथ शुरू किया गया है। ये दो अक्षर # और! फ़ाइल में पहले दो बाइट्स होना चाहिए!
विस्तृत जानकारी: http://wiki.bash-hackers.org/scripting/basics#the_shebang
नहीं, यह केवल exec
लिनक्स कर्नेल के सिस्टम कॉल द्वारा उपयोग किया जाता है , और दुभाषिया द्वारा एक टिप्पणी के रूप में व्यवहार किया जाता है
जब आप बैश पर करते हैं:
./something
लिनक्स पर, यह exec
सिस्टम कॉल को पथ के साथ कॉल करता है ./something
।
कर्नेल की इस लाइन को पास की गई फ़ाइल पर कॉल किया जाता है exec
: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25
if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
यह फ़ाइल के पहले बाइट्स को पढ़ता है, और उनकी तुलना करता है #!
।
यदि तुलना सही है, तो बाकी लाइन को लिनक्स कर्नेल द्वारा पार्स किया जाता है, जो पहले तर्क के रूप में exec
पथ /usr/bin/env python
और वर्तमान फ़ाइल के साथ एक और कॉल करता है:
/usr/bin/env python /path/to/script.py
और यह किसी भी स्क्रिप्टिंग भाषा के लिए काम करता है #
जो एक टिप्पणी चरित्र के रूप में उपयोग करता है ।
और हाँ, आप एक अनंत लूप बना सकते हैं:
printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a
बैश त्रुटि को पहचानता है:
-bash: /a: /a: bad interpreter: Too many levels of symbolic links
#!
बस मानव पठनीय होता है, लेकिन इसकी आवश्यकता नहीं है।
यदि फ़ाइल अलग-अलग बाइट्स के साथ शुरू होती है, तो exec
सिस्टम कॉल एक अलग हैंडलर का उपयोग करेगा। अन्य सबसे महत्वपूर्ण अंतर्निहित हैंडलर ELF निष्पादन योग्य फ़ाइलों के लिए है: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305 जो बाइट्स की जांच करता है 7f 45 4c 46
(जो मानव भी होता है के लिए पठनीय .ELF
)। आइए पुष्टि करते हैं कि 4 पहले बाइट्स को पढ़कर /bin/ls
, जो एक ईएलएफ निष्पादन योग्य है:
head -c 4 "$(which ls)" | hd
उत्पादन:
00000000 7f 45 4c 46 |.ELF|
00000004
इसलिए जब कर्नेल उन बाइट्स को देखता है, तो वह ईएलएफ फ़ाइल लेता है, इसे सही ढंग से मेमोरी में डालता है और इसके साथ एक नई प्रक्रिया शुरू करता है। इसे भी देखें: https://stackoverflow.com/questions/8352535/how-does-kernel-get-an-executable-binary-file-running-under-linux/31394861#3131386861
अंत में, आप binfmt_misc
तंत्र के साथ अपने खुद के शेबंग हैंडलर जोड़ सकते हैं । उदाहरण के लिए, आप फ़ाइलों के लिए.jar
एक कस्टम हैंडलर जोड़ सकते हैं । यह तंत्र फ़ाइल एक्सटेंशन द्वारा हैंडलर का भी समर्थन करता है। एक अन्य आवेदन QEMU के साथ एक अलग वास्तुकला के पारदर्शी रूप से चलाने के लिए है ।
मुझे नहीं लगता कि पोसिक्स हालांकि शेबंग्स को निर्दिष्ट करता है: https://unix.stackexchange.com/a/346214/32558 , हालांकि यह औचित्य वर्गों पर उल्लेख करता है, और "अगर निष्पादन योग्य स्क्रिप्ट सिस्टम द्वारा समर्थित हैं तो कुछ हो सकता है" हो "।
#include
। वहाँ भी,#
एक टिप्पणी के रूप में मतलब नहीं है।