क्या दुभाषिया द्वारा #! / बिन / श पढ़ा जाता है?


66

में bashया sh, मैं कुछ भी जो साथ शुरू होता है लगता है कि #एक है टिप्पणी

लेकिन bashलिपियों में हम लिखते हैं:

#!/bin/bash

और पायथन लिपियों में:

#!/bin/python

क्या इसका मतलब यह है कि #अपने आप में एक टिप्पणी है जबकि #!नहीं है?


1
और एक बार जब आप Apparmor प्रोफाइल देखना शुरू कर देंगे, तो आप देखेंगे #include। वहाँ भी, #एक टिप्पणी के रूप में मतलब नहीं है।

4
@ vasa1 लेकिन प्रमुख मुद्दा है कि अक्सर शेल स्क्रिप्ट की शुरुआत में hashbang लाइनों के बारे में सराहना नहीं कर रहा है वह यह है कि वे कर रहे हैं टिप्पणी
एलिया कगन

जवाबों:


100

#!लाइन प्रयोग किया जाता है से पहले स्क्रिप्ट चलाने है, तो ध्यान नहीं दिया जब स्क्रिप्ट चलाता है।

आप पूछ रहे हैं कि एक शेबंग लाइन और एक साधारण टिप्पणी के बीच क्या अंतर है ।

के साथ शुरू होने वाली एक लाइन #!बस किसी भी अन्य लाइन के रूप में एक टिप्पणी है जो इसके साथ शुरू होती है #। यह सच है अगर #!फ़ाइल की पहली पंक्ति है, या कहीं और। #!/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 करता है, और इसे "स्क्रिप्ट" फ़ाइल के अंत में जोड़ता है।

उपयोगी? बहुत नहीं। वैचारिक रूप से दिलचस्प है? पूरी तरह से! हाँ। (कुछ हद तक।)

वैचारिक रूप से समान प्रोग्रामिंग / स्क्रिप्टिंग अवधारणाओं (सिर्फ मनोरंजन के लिए)


@Rinzwind Thx! (Btw इस उत्तर की उत्पत्ति कहीं और नहीं होती है, यदि आप यही सोच रहे हैं।)
एलियाह कगन

@ रिनविंड चिंता मत करो, 1 घंटे के बाद 8 अपवोट्स के साथ यह बहुत अधिक बढ़ने की संभावना है :-)
गुंटबर्ट

1
यदि इसे हमेशा अनदेखा किया जाता है, तो पायथन -xध्वज क्या करता है?
जेरिट

4
@gerrit अच्छा सवाल। किसी भी भाषा में जहां इंट्राप्टर / कंपाइलर लाइन नंबर वाले संदेशों की रिपोर्ट करता है, टिप्पणियों की सामग्री को नजरअंदाज कर दिया जाता है, लेकिन टिप्पणी-पंक्तियों को अभी भी गिना जाता है । कोड की एक पंक्ति से पहले एक टिप्पणी या रिक्त लाइन जोड़ना अभी भी कोड की उस पंक्ति में परिणाम होता है जिसकी लाइन संख्या बढ़ी हुई है। -x"छोड़ें [s] पहली पंक्ति ..." दूसरी पंक्ति को 1इसके स्थान पर क्रमांकित किया जाता है 2, 2इसके बजाय तीसरी पंक्ति 3, आदि। यही कारण है कि आपको उस ध्वज का उपयोग नहीं करना चाहिए। ;) -xगैर-यूनिक्स-जैसे ओएस पर स्क्रिप्टिंग के लिए है जिसमें शेबंग जैसा सिंटैक्स होता है, जिसके साथ शुरुआत नहीं होती है #(इस तरह पायथन टिप्पणी नहीं)।
एलियाह कगन

4
पर्ल में, यदि दुभाषिया सीधे (शुरू कर दिया है perl script.plबनाम ./script.pl) तो दुभाषिया होगा जैसे झंडे पार्स करने के लिए कुटिया लाइन पढ़ -w। हालांकि इस सुविधा पर भरोसा करने की अनुशंसा नहीं की गई है।
ऑरेंजडॉग

7

एक शेबबैंग चरित्र अनुक्रम होता है जिसमें वर्ण संख्या चिह्न और विस्मयादिबोधक चिह्न (जैसे "#!") होता है, जब यह किसी स्क्रिप्ट की प्रारंभिक पंक्ति पर प्रारंभिक दो वर्णों के रूप में होता है।

* निक्स ऑपरेटिंग सिस्टम के तहत, जब एक स्क्रिप्ट एक शेबबैंग के साथ शुरू होती है, तो प्रोग्राम लोडर एक स्क्रिप्ट के प्रारंभिक लाइन के बाकी हिस्से को एक दुभाषिया निर्देश के रूप में पार्स करता है; इसके बजाय निर्दिष्ट दुभाषिया कार्यक्रम चलाया जाता है, इसे एक तर्क के रूप में पारित किया जाता है जो स्क्रिप्ट को चलाने का प्रयास करते समय शुरू में उपयोग किया जाता था। उदाहरण के लिए, यदि किसी स्क्रिप्ट का नाम "पथ / से / आपकी स्क्रिप्ट" रखा गया है, और यह निम्न पंक्ति से शुरू होती है:

#!/bin/sh

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

तदनुसार, इसे "पथ / टू / पायथन-स्क्रिप्ट" पथ के साथ एक स्क्रिप्ट का नाम दिया गया है और यह निम्न पंक्ति से शुरू होता है:

#!/bin/python

फिर लोड किए गए प्रोग्राम को पहले तर्क के रूप में "पथ / / से / पायथन-लिपि" पास करते हुए, उदाहरण के लिए प्रोग्राम "/ बिन / पाइथन" चलाने का निर्देश दिया जाता है।

संक्षेप में "#" एक पंक्ति पर टिप्पणी करेगा जबकि चरित्र अनुक्रम "#!" एक स्क्रिप्ट की प्रारंभिक पंक्ति पर पहले दो पात्रों के रूप में होने का अर्थ उपरोक्त के रूप में है।

विवरण के लिए देखें कि कुछ स्क्रिप्ट # से क्यों शुरू होती हैं! ...?

स्रोत: इस उत्तर के कुछ वर्गों से (मामूली संशोधन के साथ) प्राप्त कर रहे हैं कुटिया (Unix) पर अंग्रेजी विकिपीडिया (द्वारा विकिपीडिया योगदानकर्ताओं )। यह आलेख CC-BY-SA 3.0 के तहत लाइसेंस प्राप्त है , जो AU पर उपयोगकर्ता सामग्री के समान है, इसलिए इस व्युत्पत्ति को रोपण के साथ अनुमति दी जाती है।


4

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

सौजन्य: http://en.wikipedia.org/wiki/Shebang_%28Unix%29

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

विस्तृत जानकारी: http://wiki.bash-hackers.org/scripting/basics#the_shebang


0

नहीं, यह केवल 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 , हालांकि यह औचित्य वर्गों पर उल्लेख करता है, और "अगर निष्पादन योग्य स्क्रिप्ट सिस्टम द्वारा समर्थित हैं तो कुछ हो सकता है" हो "।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.