क्यों "# में" -! / बिन / श - “शेबंग?


28
#! / बिन / श -

क्या (या कम से कम) अक्सर एक स्क्रिप्ट की व्याख्या करने के लिए अनुशंसित शेबंग है /bin/sh

सिर्फ #! /bin/shया क्यों नहीं #!/bin/sh?

इसके लिए क्या है -?

जवाबों:


38

यही कारण है कि आपको लिखने की आवश्यकता क्यों है:

rm -- *.txt

और नहीं

rm *.txt

जब तक आप गारंटी नहीं दे सकते .txtकि वर्तमान निर्देशिका में कोई भी फाइल ऐसा नाम नहीं है जिसके साथ शुरू होता है -

में:

rm <arg>

<arg>एक विकल्प माना जाता है अगर यह -अन्यथा हटाने के लिए या फ़ाइल के साथ शुरू होता है । में

rm - <arg>

argहमेशा एक फाइल के रूप में माना जाता है, भले ही वह इसके साथ शुरू हो -या नहीं।

के लिए वही है sh

जब कोई उस स्क्रिप्ट को निष्पादित करता है जो उसके साथ शुरू होती है

#! /bin/sh

आमतौर पर इसके साथ:

execve("path/to/the-script", ["the-script", "arg"], [environ])

सिस्टम इसे रूपांतरित करता है:

execve("/bin/sh", ["/bin/sh", "path/to/the-script", "arg"], [environ])

path/to/the-scriptआम तौर पर कुछ है कि स्क्रिप्ट लेखक के नियंत्रण में नहीं है। लेखक यह अनुमान नहीं लगा सकता है कि स्क्रिप्ट की प्रतियां कहाँ संग्रहीत की जाएंगी और न ही किस नाम से। विशेष रूप से, वे गारंटी नहीं दे सकते हैं कि path/to/the-scriptजिसके साथ यह कहा जाता है वह उसके साथ शुरू नहीं होगा -(या +जो कि एक समस्या भी है sh)। इसलिए हमें विकल्पों के अंत को चिह्नित करने के लिए यहां की आवश्यकता है -

उदाहरण के लिए, मेरे सिस्टम पर zcat(ज्यादातर अन्य लिपियों की तरह) एक स्क्रिप्ट का एक उदाहरण है जो उस अनुशंसा का पालन नहीं करता है:

$ head -n1 /bin/zcat
#!/bin/sh
$ mkdir +
$ ln -s /bin/zcat +/
$ +/zcat
/bin/sh: +/: invalid option
[...]

अब आप पूछ सकते हैं कि क्यों #! /bin/sh -और क्या नहीं #! /bin/sh --?

जबकि #! /bin/sh --POSIX गोले के साथ काम करेगा, #! /bin/sh -अधिक पोर्टेबल है; विशेष रूप से प्राचीन संस्करणों के लिए shshइलाज -के रूप में और अंत के विकल्प पहले का है getopt()और इसके सामान्य प्रयोग --एक लंबे समय से विकल्पों में से अंत बताने के लिए। जिस तरह से बॉर्न शेल (70 के दशक के अंत से) ने अपने तर्कों को पार्स किया, अगर इसके साथ शुरुआत हुई तो विकल्पों के लिए केवल पहले तर्क पर विचार किया गया -। के बाद सभी पात्रों -को विकल्प नामों के रूप में माना जाएगा; अगर कोई चरित्र नहीं था -, तो कोई विकल्प नहीं था। यह अटक गया और बाद के सभी बॉर्न जैसे गोले -विकल्पों के अंत को चिह्नित करने के तरीके के रूप में पहचाने गए ।

बॉर्न शेल में (लेकिन आधुनिक बॉर्न-जैसे गोले में नहीं), #! /bin/sh -eufसमस्या के आसपास भी काम करेगा क्योंकि केवल पहले तर्क को विकल्पों पर विचार किया गया था।

अब, एक कह सकता है कि हम यहाँ पांडित्यपूर्ण हो रहे हैं, और यह भी है कि मैंने ऊपर इटैलिक में इसकी आवश्यकता क्यों लिखी है:

  1. उनके सही दिमाग में कोई भी एक ऐसी स्क्रिप्ट को नहीं कहेगा जिसके साथ कुछ शुरू होता है -या +उन्हें एक निर्देशिका में रखा जाता है जिसका नाम -या के साथ शुरू होता है +
  2. अगर उन्होंने ऐसा किया है, तो पहले एक तर्क देगा कि वे केवल खुद को दोषी ठहरा सकते हैं, लेकिन यह भी, जब आप किसी स्क्रिप्ट का आह्वान करते हैं, तो अधिक बार नहीं, यह एक शेल या execvp()/ execlp()-प्रकार कार्यों से होता है। और उस मामले में, आम तौर पर आप उन्हें या तो the-scriptइसके लिए आमंत्रित करते हैं $PATH, जिस पर execve()सिस्टम कॉल के लिए पथ तर्क आम तौर पर /( -न तो +) या ./the-scriptयदि आप the-scriptवर्तमान निर्देशिका में चलाना चाहते हैं (और तब रास्ता शुरू होता है ./, -+तो या तो)।

अब सैद्धांतिक शुद्धता मुद्दे के बगल में , एक और कारण है कि अच्छे अभ्यास के#! /bin/sh - रूप में अनुशंसित क्यों किया गया । और यह एक ऐसे समय में वापस जाता है जहां कई प्रणालियों ने अभी भी सेटिड स्क्रिप्ट का समर्थन किया है।

यदि आपके पास एक स्क्रिप्ट है जिसमें शामिल हैं:

#! /bin/sh
/bin/echo "I'm running as root"

और उस स्क्रिप्ट को रूट ( -r-sr-xr-x root binअनुमतियों के साथ ) की तरह , उन प्रणालियों पर, जब एक साधारण उपयोगकर्ता द्वारा निष्पादित किया जाता है, द

execve("/bin/sh", ["/bin/sh", "path/to/the-script"], [environ])

के रूप में किया जाएगा root!

यदि उपयोगकर्ता ने एक सिमलिंक बनाया /tmp/-i -> path/to/the-scriptऔर इसे निष्पादित किया -i, तो यह एक इंटरेक्टिव शेल ( /bin/sh -i) शुरू करेगा root

-आस-पास काम होता है कि (यह आस-पास काम नहीं होता दौड़ शर्त मुद्दा , या तथ्य यह है कि कुछ shकुछ की तरह कार्यान्वयन ksh88आधारित लोगों के बिना स्क्रिप्ट तर्क देखने होगा /में $PATHहै)।

आजकल, शायद ही कोई सिस्टम किसी भी समय स्क्रिप्ट को सेट करने में सहायता करता है, और उनमें से कुछ जो अभी भी करते हैं (आमतौर पर डिफ़ॉल्ट रूप से नहीं), अंत में एक execve("/bin/sh", ["/bin/sh", "/dev/fd/<n>", arg])( <n>स्क्रिप्ट पर पढ़ने के लिए एक फ़ाइल विवरणक खुला है) जो इस मुद्दे और दोनों के आसपास काम करता है दौड़ की स्थिति।

ध्यान दें कि आपको अधिकांश दुभाषियों के साथ समान मुद्दे मिलते हैं, न कि बॉर्न जैसे गोले। गैर-बॉर्न जैसे गोले आमतौर पर -अंत-विकल्प मार्कर के रूप में समर्थन नहीं करते हैं , लेकिन आम तौर पर --इसके बजाय (कम से कम आधुनिक संस्करणों के लिए) समर्थन करते हैं।

भी

#! /usr/bin/awk -f
#! /usr/bin/sed -f

के रूप में अगले तर्क के लिए एक तर्क के रूप में माना जाता है इस मुद्दे को नहीं है -fकिसी भी मामले में विकल्प, लेकिन यह अभी भी काम करता है, तो ऐसा नहीं करता path/to/scriptहै -(इस स्थिति में, अधिकांश के साथ sed/ awkकार्यान्वयन, sed/ awkसे कोड को पढ़ने के लिए नहीं है -फ़ाइल, लेकिन इसके बजाय स्टडिन से)।

यह भी ध्यान दें कि अधिकांश प्रणालियों पर, कोई उपयोग नहीं कर सकता है:

#! /usr/bin/env sh -
#! /usr/bin/perl -w --

अधिकांश प्रणालियों के रूप में शेबबैंग तंत्र दुभाषिया पथ के बाद केवल एक तर्क की अनुमति देता है।

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

यूनिक्स शेबंग के बारे में एक बहुत अच्छा संदर्भ https://www.in-ulm.de/~mascheck/various/hehebang पर पाया जा सकता है


1
क्या इससे #? / बिन / बैश की कोई प्रासंगिकता है?
जो

1
@ जो, बेशक, bashहर दूसरे शेल की तरह विकल्प स्वीकार करता है। बॉर्न-जैसा और पोसिक्स शेल होने के नाते, bashदोनों को स्वीकार करता है #! /bin/bash -और #! /bin/bash --
स्टीफन चेज़लस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.