क्या शेबंग उस शेल को निर्धारित करता है जो स्क्रिप्ट चलाता है?


84

यह एक मूर्खतापूर्ण प्रश्न हो सकता है, लेकिन मैं इसे अभी भी पूछता हूं। अगर मैंने शेबंग घोषित किया है

#!/bin/bash 

की शुरुआत में my_shell_script.sh, इसलिए मुझे हमेशा बैश का उपयोग करके इस स्क्रिप्ट को लागू करना होगा

[my@comp]$bash my_shell_script.sh

या मैं जैसे उपयोग कर सकते हैं

[my@comp]$sh my_shell_script.sh

और मेरी स्क्रिप्ट शेबंग का उपयोग करके रनिंग शेल को निर्धारित करती है? क्या kshशेल के साथ भी ऐसा ही हो रहा है ? मैं AIX का उपयोग कर रहा हूं।


6
आपकी ओर से थोड़ा भ्रम है: जब आप "_some_shell some_script" करते हैं तो यह _some_shell शुरू होता है और इसे some_script की व्याख्या करने के लिए कहता है। तो नहीं, अगर आप "sh my_shell_script.sh" करते हैं, तो यह शेबंग की व्याख्या नहीं करेगा, लेकिन इसके बजाय स्क्रिप्ट की व्याख्या करेगा। शेबंग का उपयोग करने के लिए: chmod +x my_shell_script.sh ; /path/to/my_shell_script.sh # or ./my_shell_script.sh if you happen to be in its directory
ओलिवियर दुलैक

जवाबों:


117

मामला #! एक के एक मानव पठनीय उदाहरण है जादुई संख्या बाइट स्ट्रिंग से मिलकर 0x23 0x21, जिसके द्वारा प्रयोग किया जाता है exec()कार्यों के परिवार निर्धारित करने के लिए फ़ाइल निष्पादित करने के लिए एक स्क्रिप्ट या एक द्विआधारी है। जब शेबंग मौजूद होता है, exec()तो उसके बदले शेलबैंग के बाद निर्दिष्ट निष्पादन योग्य चला जाएगा।

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

इसलिए, जैसा कि अन्य ने नोट किया है, यदि आप exec()शेबंग लाइन पर निर्दिष्ट दुभाषिया को आमंत्रित करना चाहते हैं , तो स्क्रिप्ट के पास निष्पादन योग्य बिट सेट और के रूप में होना चाहिए ./my_shell_script.sh

व्यवहार निम्न स्क्रिप्ट के साथ प्रदर्शित करना आसान है:

#!/bin/ksh
readlink /proc/$$/exe

स्पष्टीकरण:

  • #!/bin/kshkshदुभाषिया होने को परिभाषित करता है।

  • $$ वर्तमान प्रक्रिया के पीआईडी ​​रखती है।

  • /proc/pid/exe प्रक्रिया के निष्पादन योग्य के लिए एक सहानुभूति है (कम से कम लिनक्स पर, AIX पर, /proc/$$/object/a.out निष्पादन योग्य के लिए एक लिंक है)।

  • readlink प्रतीकात्मक लिंक के मूल्य का उत्पादन करेगा।

उदाहरण:

नोट : मैं उबंटू, जहां डिफ़ॉल्ट खोल पर इस प्रदर्शन कर रहा हूँ /bin/shकरने के लिए एक सिमलिंक है पानी का छींटा यानी /bin/dashऔर /bin/kshकरने के लिए एक सिमलिंक है /etc/alternatives/ksh, जो बारी में करने के लिए एक सिमलिंक है /bin/pdksh

$ chmod +x getshell.sh
$ ./getshell.sh 
/bin/pdksh
$ bash getshell.sh 
/bin/bash
$ sh getshell.sh 
/bin/dash

इस उत्तर के लिए धन्यवाद थॉमस। Pretend हम स्क्रिप्ट को Node.js या Java या जो भी हो, से एक बच्चे की प्रक्रिया के रूप में लॉन्च करते हैं। क्या हम "निष्पादित" प्रक्रिया शुरू कर सकते हैं, और फिर निष्पादन शेल स्क्रिप्ट चलाएगा? मैं पूछता हूं कि मैं इस प्रश्न का उत्तर ढूंढ रहा हूं: stackoverflow.com/questions/41067872/…
अलेक्जेंडर मिल्स

1
@AlexanderMills exec()इस उत्तर में निर्दिष्ट एक सिस्टम कॉल है, कमांड execएक शेल बिलिन है, यही वजह है कि आप Node.js या Java से किसी exec प्रोग्राम को आमंत्रित नहीं कर सकते हैं । हालाँकि, Runtime.exec()जावा में उदाहरण के लिए किसी भी शेल कमांड को अंततः exec()सिस्टम कॉल द्वारा संसाधित किया जाता है।
थॉमस निमन

हु, हाँ, मैं वास्तव में जावा एपीआई से परिचित हूँ जिसका आपने अभी उल्लेख किया है, मुझे आश्चर्य है कि अगर निचले स्तर के निष्पादन () को किसी तरह से कॉल करने का एक तरीका है
अलेक्जेंडर मिल्स

@AlexanderMills मुझे लगता है कि child_process.{exec(),execFile(),spawn()सभी को C exec()(के माध्यम से process) लागू किया जाएगा ।
थॉमस निमन

10

हाँ यह करता है। वैसे यह कोई मूर्खतापूर्ण सवाल नहीं है। मेरे उत्तर का एक संदर्भ यहाँ है । # के साथ एक स्क्रिप्ट शुरू करना!

  • इसे एक शबंग या "बैंग" लाइन कहा जाता है।

  • यह बाश दुभाषिया के लिए निरपेक्ष मार्ग के अलावा कुछ भी नहीं है।

  • इसमें एक संख्या चिन्ह और एक विस्मयादिबोधक बिंदु वर्ण (#!) होता है, जिसके बाद दुभाषिया जैसे / बिन / बैश के लिए पूर्ण पथ होता है।

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

एक दुभाषिया रेखा की अनदेखी

यदि आप दुभाषिया लाइन निर्दिष्ट नहीं करते हैं, तो डिफ़ॉल्ट आमतौर पर / बिन / श होता है। लेकिन, यह अनुशंसा की जाती है कि आप #! / Bin / bash लाइन सेट करें।


3
विस्तृत करने के लिए, कर्नेल केवल जानता है कि सांख्यिकीय रूप से जुड़े बायनेरिज़ को कैसे निष्पादित किया जाए और दूसरों के लिए दुभाषिया जानकारी कैसे प्राप्त करें (बाइनरी में एक विशेष क्षेत्र, या शेलबैंग लाइन)। आमतौर पर शेल स्क्रिप्ट को निष्पादित करने का अर्थ है शेल के लिए शेलंग लाइन का अनुसरण करना, और फिर डायनेमिक लिंकर को शेल बाइनरी में DT_INTERP फ़ील्ड का अनुसरण करना।
साइमन रिक्टर

5
यह भी ध्यान दें कि यह शेल स्क्रिप्ट तक सीमित नहीं है। सभी पाठ आधारित स्क्रिप्ट फ़ाइलें इसका उपयोग करती हैं। उदाहरण के #!/usr/bin/perl #!/usr/local/bin/python #!/usr/local/bin/rubyलिए, कई प्रणालियों का समर्थन करने के लिए उपयोग की जाने वाली एक अन्य सामान्य शेबंग प्रविष्टि है, जिसमें आप जिस दुभाषिया का उपयोग करना चाहते हैं उसका पता लगाने के लिए env का उपयोग करना है, जैसे#!/usr/bin/env perl #!/usr/bin/env python
sambler

@sambler का बोलना env, जिसे वास्तव में पसंद किया जाना चाहिए? पायथन और पर्ल अक्सर envगोले का उपयोग करते हैं , जबकि यह अक्सर छोड़ा जाता है और शेलंग प्रश्न में शेल को इंगित करता है।
पोल्मन

1
@ पॉलीमोन को कम पसंद किया जाता है और जिस पर रास्ते अलग-अलग होते हैं। सभी प्रणालियों पर मूल गोले समान पथ में हैं। अद्यतित पर्ल और पायथन के विभिन्न संस्करणों को अलग-अलग स्थानों पर अलग-अलग स्थानों पर स्थापित किया जा सकता है, इसलिए env का उपयोग करके एक ही शेबंग को हमेशा काम करने की अनुमति मिलती है, यही कारण है कि शेल स्क्रिप्ट की तुलना में env का उपयोग पर्ल और पायथन स्क्रिप्ट के साथ अधिक किया जाता है।
साम्बलर

env$ PATH में एक प्रोग्राम खोजने के लिए एक हैक का एक सा है। यह नाम की तरह पर्यावरण चर सेट नहीं करता है। $ PATH विभिन्न उपयोगकर्ताओं के लिए एक अलग परिणाम हो सकता है। लेकिन यह स्क्रिप्ट को बिना सिस्टम में संशोधन के चलाने में मदद करता है जो उचित विषम इंटरप्रेटर को किसी विषम स्थान पर रखता है।
जॉन महोवाल

4

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 के साथ एक अलग वास्तुकला के पारदर्शी रूप से चलाने के लिए है ।

मुझे नहीं लगता कि POSIX शेबन्स को निर्दिष्ट करता है, हालांकि: https://unix.stackexchange.com/a/346214/32558 , हालांकि यह इसका उल्लेख औचित्य वर्गों में करता है, और फॉर्म में "यदि निष्पादन योग्य स्क्रिप्ट सिस्टम द्वारा समर्थित हैं तो कुछ हो सकता है"।


1
./somethingशेल से चलने से पूरा रास्ता पास नहीं होगा exec, लेकिन वास्तव में रास्ता प्रवेश कर गया। क्या आप अपने जवाब में इसे सही कर सकते हैं? क्या echo "$0"अपनी स्क्रिप्ट में और आप यह मामला है देखेंगे।
एंडी डॉग जूल

2

वास्तव में, यदि आप इसे परिणामी रूप से लेते हैं, तो निष्पादन योग्य शेबंग लाइन में नोट किया गया, बस एक निष्पादन योग्य है। यह कुछ पाठ दुभाषिया को निष्पादन योग्य के रूप में उपयोग करने के लिए समझ में आता है, लेकिन यह आवश्यक नहीं है। स्पष्टीकरण और प्रदर्शन के लिए, मैंने एक बेकार परीक्षा की:

#!/bin/cat
useless text
more useless text
still more useless text

फ़ाइल test.txt का नाम दिया और एक्सटेक्टेबल बिट सेट किया chmod u+x test.txt, फिर "इसे" कहा ./test.txt:। जैसा कि अपेक्षित था, फ़ाइल की सामग्री आउटपुट है। इस मामले में, बिल्ली शेबंग रेखा की उपेक्षा नहीं करती है। यह बस सभी लाइनों को आउटपुट करता है। किसी भी उपयोगी दुभाषिया इस प्रकार इस शबंग रेखा को अनदेखा करने में सक्षम होना चाहिए। बैश, पर्ल और PHP के लिए, यह केवल एक टिप्पणी लाइन है। तो हाँ, ये चरवाहे रेखा को अनदेखा करते हैं।


-1

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

संक्षेप में, इससे कोई फर्क नहीं पड़ता कि आप किस शेल को स्क्रिप्ट के साथ आमंत्रित करते हैं - कर्नेल निष्पादन को उचित तरीके से भेज देगा।


4
के बीच एक चिह्नित अंतर है bash ./myscript.shऔर ./myscript.sh
एक CVN

इस "चिह्नित अंतर" से आपका क्या मतलब है?
jrara

3
@ जरा मेरा जवाब देखें, यह कथन कि "इससे कोई फर्क नहीं पड़ता कि आप किस शेल को स्क्रिप्ट के साथ आमंत्रित करते हैं" बस सच नहीं है।
थॉमस निमन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.