2010-06-09 5 views
37

एक स्क्रिप्ट में आपको स्क्रिप्ट निष्पादित करने वाले प्रोग्राम के पथ के बाद पहली पंक्ति पर #! शामिल करना होगा (उदाहरण: sh, perl)।# कैसे करता है! शेबांग काम?

जहाँ तक मुझे पता है, # चरित्र एक टिप्पणी की शुरुआत को दर्शाता है और उस पंक्ति को स्क्रिप्ट निष्पादित करने वाले कार्यक्रम द्वारा अनदेखा किया जाना चाहिए। ऐसा प्रतीत होता है कि स्क्रिप्ट को उचित कार्यक्रम द्वारा निष्पादित करने के लिए यह पहली पंक्ति कुछ बिंदु पर पढ़ी जाती है।

क्या कोई #! की कार्यप्रणाली पर अधिक प्रकाश डाल सकता है?

मैं इस बारे में वास्तव में उत्सुक हूं, इसलिए अधिक गहराई से उत्तर बेहतर है।

+0

मैं comp.lang.shell सूत्र में इस विषय [निष्पादन उपसंहार कार्यक्रमों] (http://groups.google पर एक अच्छी स्कूली शिक्षा मिल गया। कॉम/समूह/comp.unix.shell/ब्राउज_थ्रेड/थ्रेड/ई 7 ए 3306342 सी 01847/ec5741ed3278408a? q = निष्पादन योग्य + पोस्टस्क्रिप्ट + प्रोग्राम # ec5741ed3278408a) कमांड लाइन में हेरफेर करने के लिए एक सरल सी प्रोग्राम लिखकर, मैं निष्पादन योग्य स्क्रिप्ट बनाने में सक्षम था भाषा जो आम तौर पर ऐसा नहीं करती है। –

उत्तर

30

अनुशंसित पढ़ने:

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

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

+0

था सबसे अच्छी बात यह है कि फ़ाइल कुछ भी हो सकती है, जरूरी नहीं कि एक कार्यक्रम - जब तक कि कार्यक्रम प्रोग्राम शेबांग को सहन कर सके। –

+0

@ केविनपैंको: क्या यह हमेशा 16 बिट्स है जो कर्नेल के प्रोग्राम लोडर द्वारा चेक किए जाते हैं? तब क्या होगा यदि '#! 'पहले यूटीएफ -8 या यूटीएफ -16 बीओएम द्वारा किया गया था? – stakx

+1

@stakx हां, यह यूनिकोड से पहले आविष्कार किया गया था और तब से नहीं बदला गया है। http://unicode.org/faq/utf_bom.html#bom5 –

8

लघु कहानी: कुटिया (#!) लाइन से खोल पढ़ा जाता है (उदाहरण के लिए sh, bash, आदि) ऑपरेटिंग सिस्टम के कार्यक्रम लोडर। हालांकि यह औपचारिक रूप से एक टिप्पणी की तरह दिखता है, तथ्य यह है कि फ़ाइल के पहले दो बाइट्स पूरी फ़ाइल को टेक्स्ट फ़ाइल के रूप में और एक स्क्रिप्ट के रूप में चिह्नित करते हैं। शेबैंग के बाद पहली पंक्ति पर वर्णित निष्पादन योग्य को लिपि पारित की जाएगी। देखा!


थोड़ा लंबा कहानी: कल्पना कीजिए कि आप निष्पादन योग्य बिट (x) सेट के साथ, अपनी स्क्रिप्ट, foo.sh है। इस फ़ाइल में उदा। निम्नलिखित:

#!/bin/sh 

# some script commands follow...: 
# *snip* 

अब, अपने खोल पर, आप टाइप करें:

> ./foo.sh 

संपादित करें: कृपया यह भी टिप्पणी नीचे के बाद या आप निम्नलिखित पढ़ा से पहले पढ़ें! जैसा कि यह पता चला, मैं गलत था। यह स्पष्ट रूप से वह शेल नहीं है जो स्क्रिप्ट को लक्षित दुभाषिया को पास करता है, लेकिन ऑपरेटिंग सिस्टम (कर्नेल) स्वयं ही।

याद रखें कि आप खोल प्रक्रिया के अंदर इस टाइप कि (मान लेते हैं इस कार्यक्रम /bin/sh है भी नहीं)। इसलिए, उस इनपुट द्वारा उस इनपुट को संसाधित करना होगा। यह इस पंक्ति को कमांड के रूप में व्याख्या करता है, क्योंकि यह पता चलता है कि लाइन पर दर्ज की गई पहली चीज़ एक फ़ाइल का नाम है जो वास्तव में मौजूद है और जिसमें निष्पादन योग्य बिट सेट है।

/bin/sh फिर फ़ाइल की सामग्री को पढ़ना शुरू कर देता है और फ़ाइल की शुरुआत में शेबैंग (#!) को ठीक से खोजता है। खोल के लिए, यह एक टोकन ("जादू संख्या") है जिसके द्वारा यह जानता है कि फ़ाइल में एक स्क्रिप्ट है।

अब, यह कैसे पता चलता है कि स्क्रिप्ट को कौन सी प्रोग्रामिंग भाषा लिखा है? आखिरकार, आप बैश स्क्रिप्ट्स, पर्ल स्क्रिप्ट्स, पायथन स्क्रिप्ट्स को निष्पादित कर सकते हैं ... सभी खोल अब तक जानते हैं कि यह एक स्क्रिप्ट फ़ाइल को देख रहा है (जो एक बाइनरी फ़ाइल नहीं है, लेकिन एक टेक्स्ट फ़ाइल है)। इस प्रकार यह पहली पंक्ति ब्रेक तक अगला इनपुट पढ़ता है (जिसके परिणामस्वरूप /bin/sh होगा, उपर्युक्त के साथ तुलना करें)। यह दुभाषिया है जिसके लिए स्क्रिप्ट निष्पादन के लिए पारित किया जाएगा। (इस विशेष मामले में, लक्ष्य दुभाषिया स्वयं खोल है, इसलिए इसे स्क्रिप्ट के लिए एक नया खोल नहीं डालना पड़ता है; यह बस बाकी स्क्रिप्ट फ़ाइल को संसाधित करता है।)

यदि स्क्रिप्ट नियत थी उदाहरण के लिए/bin/perl, पर्ल दुभाषिया (वैकल्पिक रूप से) को यह करना है कि यह देखने के लिए कि शेबांग लाइन वास्तव में पर्ल दुभाषिया का उल्लेख करती है या नहीं। यदि नहीं, तो पर्ल दुभाषिया को पता चलेगा कि यह इस स्क्रिप्ट को निष्पादित नहीं कर सकता है। यदि वास्तव में शेबांग लाइन में पर्ल दुभाषिया का उल्लेख किया गया है, तो यह बाकी स्क्रिप्ट फ़ाइल को पढ़ता है और इसे निष्पादित करता है।

+4

निष्पादन योग्य के पहले दो बाइट्स जादू संख्या हैं जो इंगित करती हैं कि इसे कैसे निष्पादित किया जाना चाहिए; व्याख्या की गई स्क्रिप्ट के लिए, पहले दो बाइट आसानी से ASCII वर्णों के अनुरूप होते हैं '#!' – friedo

+7

यह वह शेल नहीं है जो उन दो बाइट्स को देख रहा है, यह सिस्टम (प्रोग्राम लोडर) है, हाँ? वही बात होती है कि आप स्क्रिप्ट के अंदर से स्क्रिप्ट चला रहे हैं या नहीं। – Cascabel

+4

शेबांग को खोल द्वारा नियंत्रित नहीं किया जाता है, इसे ओएस द्वारा ही नियंत्रित किया जाता है। –

1

लिनक्स कर्नेल exec सिस्टम कॉल प्रारंभिक बाइट्स #! का उपयोग करता है फ़ाइल प्रकार की पहचान करने के

आप बैश पर करते हैं:

./something 
लिनक्स पर

, इस पूर्ण साथ exec सिस्टम कॉल कॉल something का मार्ग।

इस लाइन फ़ाइल exec के लिए पारित पर कर्नेल में बुलाया जाता है: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25

अगर ((bprm-> buf [0] = '#') || (bprm-> buf [1 ]! = '!'))

यह फ़ाइल के पहले बाइट्स को पढ़ता है, और उन्हें #! से तुलना करता है।

तो तुलना सत्य है, तभी लाइन के बाकी लिनक्स कर्नेल, जो पथ /usr/bin/env python और पहले तर्क के रूप में वर्तमान फ़ाइल के साथ एक और कार्यकारी कॉल करता है के द्वारा पार्स किया गया है:

/usr/bin/env python /path/to/script.py 

और इस के लिए काम करता है कोई भी स्क्रिप्टिंग भाषा जो टिप्पणी चरित्र के रूप में # का उपयोग करती है।

#!/a 

और एक निष्पादन योग्य फ़ाइल पथ पर /a

#! मानव पठनीय है, लेकिन यह आवश्यक नहीं है:

हाँ, आप अनंत लूप के साथ कर सकते हैं।

फ़ाइल अलग बाइट्स के साथ शुरू हुई थी, तो exec सिस्टम कॉल एक अलग हैंडलर का उपयोग करेगा।दूसरा सबसे महत्वपूर्ण अंतर्निहित हैंडलर ईएलएफ निष्पादन योग्य फाइलों के लिए है: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305 जो बाइट्स 7f 45 4c 46 (जो .ELF के लिए मानव पठनीय भी होता है) के लिए जांचता है, जो एल्फ़ फ़ाइल को पढ़ता है, इसे स्मृति में सही तरीके से रखता है, और एक नई प्रक्रिया शुरू करता है यह। यह भी देखें: How does kernel get an executable binary file running under linux?

इसके अलावा, आप अपने खुद के शेबैंग हैंडलर binfmt_misc तंत्र जोड़ सकते हैं। उदाहरण के लिए, आप .jar फ़ाइलों के लिए एक कस्टम हैंडलर जोड़ सकते हैं: Running a JAR file without directly calling `java` यह तंत्र फ़ाइल एक्सटेंशन द्वारा हैंडलर का भी समर्थन करता है। http://stackoverflow.com/questions/3009192/how-does-the-shebang-work/40938907#40938907

मुझे नहीं लगता कि POSIX तथापि shebangs निर्दिष्ट करता है: https://unix.stackexchange.com/a/346214/32558