किस शेल दुभाषिया में कोई शेबंग के साथ स्क्रिप्ट चलती है?


17

मान लीजिए कि मेरे खाते के लिए डिफ़ॉल्ट शेल zsh है, लेकिन मैंने टर्मिनल खोला और बैश को निकाल दिया और स्क्रिप्ट का नाम दिया prac002.sh, स्क्रिप्ट, zsh या बैश को निष्पादित करने के लिए किस शेल इंटरप्रेटर का उपयोग किया जाएगा? निम्नलिखित उदाहरण पर विचार करें:

papagolf@Sierra ~/My Files/My Programs/Learning/Shell % sudo cat /etc/passwd | grep papagolf
[sudo] password for papagolf: 
papagolf:x:1000:1001:Rex,,,:/home/papagolf:/usr/bin/zsh
# papagolf's default shell is zsh

papagolf@Sierra ~/My Files/My Programs/Learning/Shell % bash
# I fired up bash. (See that '%' prompt in zsh changes to '$' prompt, indicating bash.)

papagolf@Sierra:~/My Files/My Programs/Learning/Shell$ ./prac002.sh 
Enter username : Rex
Rex
# Which interpreter did it just use?

** संपादित करें: ** यहाँ स्क्रिप्ट की सामग्री है

papagolf@Sierra ~/My Files/My Programs/Learning/Shell % cat ./prac002.sh 
read -p "Enter username : " uname
echo $uname

शीर्ष पर स्क्रिप्ट क्या कहती है?
माइकल होमर

@ मिचेलहोमर: कुछ नहीं। मैंने केवल स्क्रिप्ट की सामग्री को जोड़ने के लिए प्रश्न संपादित किया। स्क्रिप्ट में निष्पादन योग्य अनुमति है।
7_R3X

यदि आप वर्तमान शेल का उपयोग करना चाहते हैं, तो इसे डॉट सोर्स का उपयोग करें, जैसे . prac002.shकि आपकी स्क्रिप्ट वर्तमान dir में है।
ऐसपीरी

1
चलाएं . ./prac002.shऔर यह .आपकी स्क्रिप्ट के पथ के बाद वर्तमान शेल, डॉट, ( ), स्पेस () के साथ चलेगा । इसे डॉट-सोर्सिंग योर स्क्रिप्ट कहा जाता है। ;-)
आकाशवाणी

जवाबों:


19

चूँकि स्क्रिप्ट एक #!शेबंग रेखा से शुरू नहीं होती है जो यह दर्शाती है कि किस दुभाषिया का उपयोग करना है, POSIX का कहना है कि :

यदि execl()POSIX.1-2008 के सिस्टम इंटरफेसेस वॉल्यूम में परिभाषित [ENOEXEC] त्रुटि के बराबर त्रुटि के कारण फ़ंक्शन विफल हो जाता है, तो शेल एक कमांड को निष्पादित करेगा , जो खोज के परिणामस्वरूप प्राप्त होने वाले pathname के साथ एक शेल को लागू करने के बराबर होगा। ऑपरेंड , किसी भी शेष तर्कों के साथ नए शेल में चला गया, सिवाय इसके कि नए शेल में "$ 0" का मान कमांड नाम पर सेट किया जा सकता है। यदि निष्पादन योग्य फ़ाइल एक पाठ फ़ाइल नहीं है, तो शेल इस कमांड निष्पादन को बायपास कर सकता है। इस स्थिति में, यह एक त्रुटि संदेश लिखेगा, और 126 की निकास स्थिति लौटाएगा।

यह वाक्यांश थोड़ा अस्पष्ट है, और अलग-अलग गोले की अलग-अलग व्याख्या है।

इस मामले में, बैश स्वयं का उपयोग करके स्क्रिप्ट चलाएगा । दूसरी ओर, यदि आप इसे बजाय zsh से चलाते हैं, तो इसके बजाय zsh उपयोग करेगाsh (जो भी आपके सिस्टम पर है)।

आप स्क्रिप्ट में इन पंक्तियों को जोड़कर इस स्थिति के लिए उस व्यवहार को सत्यापित कर सकते हैं:

echo $BASH_VERSION
echo $ZSH_VERSION

आप ध्यान दें कि, बैश से, पहली पंक्ति आपके संस्करण का आउटपुट करती है, जबकि दूसरा कभी भी कुछ भी नहीं कहता है, कोई फर्क नहीं पड़ता कि आप किस शेल का उपयोग करते हैं।

  • अगर आपका /bin/sh है, तो कहो, dashतो जब zsh या डैश से स्क्रिप्ट निष्पादित की जाती है तो न तो लाइन कुछ भी आउटपुट करेगी।
  • अगर आपका /bin/sh बैश का लिंक है, तो आपको सभी मामलों में पहली पंक्ति का आउटपुट दिखाई देगा।
  • अगर /bin/shएक अलग संस्करण है आप सीधे उपयोग कर रहे हैं तो बैश है, जब आप सीधे bash से और zsh से स्क्रिप्ट चलाते हैं तो आपको अलग आउटपुट दिखाई देगा।

ps -p $$Rools के जवाब से आदेश भी आदेश खोल स्क्रिप्ट निष्पादित करने के लिए प्रयोग किया जाता है के बारे में उपयोगी जानकारी दिखाएगा।


मैंने अपवित्र किया, हालांकि, यदि कोई शेलबंग निर्दिष्ट नहीं किया गया है, तो जो भी डिफ़ॉल्ट शेल आपने निर्दिष्ट किया है, वह डिफाल्ट शेल का उपयोग करता है। यही कारण है कि आपको हमेशा, imho, एक शेल्बा निर्दिष्ट करना चाहिए।
एस्केपी

4
ऐसा नहीं है, जो वास्तव में जवाब का पूरा बिंदु था। आपका दूसरा वाक्य निश्चित रूप से सत्य है।
माइकल होमर

आप सही हैं, बैश इसे खुद का उपयोग करके चलाता है, मेरे अधिकांश बक्से पर डिफ़ॉल्ट शेल होता है .... बैश, वहाँ से मेरा भ्रम। मैंने अभी Solaris 8 पर ksh के साथ डिफ़ॉल्ट शेल के रूप में परीक्षण किया है, निश्चित रूप से पर्याप्त है, बैश इसे बैश के रूप में चलाता है ... आज कुछ नया सीखा, धन्यवाद (upvoted!) ;-)
8:38 पर thecarpy

धन्यवाद। क्या execl()कॉल की विफलता तब होती है जब एक शेल स्क्रिप्ट में एक शेलबैंग नहीं होता है और इसे निष्पादित किया जाता है scriptname? क्या ऐसा नहीं होता है जब एक शेल स्क्रिप्ट को निष्पादित किया जाता है bash scriptname? क्या ऐसा नहीं होता है जब एक शेल स्क्रिप्ट में एक शेबंग होता है और इसे निष्पादित किया जाता है scriptname?
All


7

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

तब क्या होता है, एप्लिकेशन और / या लाइब्रेरी फंक्शन कमांड को निष्पादित करने के लिए उपयोग किया जाता है।

यह उदाहरण के लिए एक शेल, execlp()/ execvp()libc फ़ंक्शन हो सकता है।

जब वे कमांड चलाते हैं, तो अधिकांश अन्य एप्लिकेशन उन दोनों में से किसी एक का उपयोग करेंगे। वे उदाहरण के लिए system("command line")libc फ़ंक्शन के माध्यम से शेल खोलेंगे, जो आम तौर पर shउस कमांड लाइन को पार्स करने के लिए आमंत्रित करेगा (जिसका पथ संकलन समय पर निर्धारित किया जा सकता है (जैसे /bin/shबनाम)/usr/xpg4/bin/sh सोलारिस पर)), या $SHELLस्वयं द्वारा संग्रहीत शेल को आमंत्रित करें viइसकी !कमांड, या xterm -e 'command line'कई अन्य कमांड के साथ ( su user -cउपयोगकर्ता के लॉगिन शेल को बदले में देगा $SHELL)।

आम तौर पर, एक शेबंग-लेस टेक्स्ट फ़ाइल जो शुरू नहीं होती #है, उसे shस्क्रिप्ट के रूप में माना जाता है । कौन सा shयह हालांकि अलग-अलग होगा है।

execlp()/ execvp(), execve()लौटने पर ENOEXECआम तौर shपर उस पर आह्वान किया जाएगा। उन प्रणालियों के लिए जिनके पास एक से अधिक हैं, shक्योंकि वे एक से अधिक मानक के अनुरूप हो सकते हैं, जो shकि आम तौर पर संकलन समय पर निर्धारित किया जाएगा ( कोड का उपयोग करके execvp()/ execlp()कोड के एक अलग ब्लॉब को लिंक करके जो एक अलग पथ को संदर्भित करता है sh)। उदाहरण के लिए, सोलारिस पर, वह या तो /usr/xpg4/bin/sh(एक मानक, POSIX sh) या /bin/sh(बॉर्न शेल (एक प्राचीन शैल) सोलारिस 10 पर और पुराने, ksh93 सोलारिस 11 में) होगा।

जब गोले की बात आती है, तो बहुत भिन्नता होती है। bash, एटी एंड टी ksh, बॉर्न शेल आम तौर पर स्क्रिप्ट की व्याख्या खुद करेगा (एक बच्चे की प्रक्रिया में जब तक execउपयोग नहीं किया जाता है) एक सिम्युलेटेड होने के बाद execve(), वह सभी unexported चर को बंद कर देता है, सभी बंद-पर-एफडीएस बंद कर देता है, सभी कस्टम जाल हटा दिए गए हैं, उपनाम, कार्य ... ( bashमें स्क्रिप्ट की व्याख्या करेंगेsh मोड )। yashखुद को निष्पादित करेंगे (के साथ shके रूप में argv[0]तो में shयह व्याख्या करने के लिए मोड)।

zsh, pdksh , ashआधारित गोले आम तौर पर लागू करेगाsh (पथ संकलन समय में जिनमें से निर्धारित)।

के लिए cshऔर tcsh(और shकुछ शुरुआती BSDs के), फ़ाइल का पहला वर्ण है अगर# , तो वे खुद को यह व्याख्या करने के लिए, और निष्पादित करेंगे shअन्यथा। यह एक पूर्व-शेबांग समय पर वापस जाता है जहां टिप्पणियों के रूप में cshपहचाना #जाता है, लेकिन बॉर्न शेल नहीं, इसलिए #यह संकेत था कि यह एक csh स्क्रिप्ट थी।

fish (कम से कम संस्करण 2.4.0), बस एक त्रुटि देता है अगर execve() विफल रहता है (यह एक स्क्रिप्ट के रूप में इलाज करने का प्रयास नहीं करता है)।

कुछ गोले (जैसे) bash या एटी एंड टीksh ) पहले हेयुरिस्टिकली यह निर्धारित करने की कोशिश करेंगे कि फाइल का मतलब स्क्रिप्ट है या नहीं। तो आप पा सकते हैं कि कुछ गोले एक स्क्रिप्ट को निष्पादित करने से इंकार कर देंगे अगर यह पहले कुछ बाइट्स में एक एनयूएल चरित्र मिला है।

यह भी ध्यान दें कि यदि execve() ENOEXEC के साथ विफल रहता है, लेकिन फ़ाइल में एक शेलबैंग लाइन है, तो कुछ गोले उस शेलबैंग लाइन की व्याख्या करने की कोशिश करते हैं।

तो कुछ उदाहरण:

  • जब $SHELLहै /bin/bash, विधा में व्याख्या की xterm -e 'myscript with args'जाएगी । के साथ , का उपयोग करेंगे , तो स्क्रिप्ट द्वारा व्याख्या की जाएगीmyscriptbashshxterm -e myscript with argsxtermexecvp()sh
  • su -c myscriptसोलारिस 10 पर जहां rootलॉगिन शेल है /bin/shऔर /bin/shबोर्न शेल हैmyscript व्याख्या ।
  • /usr/xpg4/bin/awk 'BEGIN{system("myscript")' सोलारिस 10 पर इसकी व्याख्या की जाएगी /usr/xpg4/bin/sh (उसी के लिए /usr/xpg4/bin/env myscript) की जाएगी।
  • find . -prune -exec myscript {} \;सोलारिस 10 पर (उपयोग करके execvp()) इसकी व्याख्या की जाएगी/bin/sh भी साथ /usr/xpg4/bin/find, यहां तक कि एक POSIX पर्यावरण (एक अनुरूपता बग) में।
  • csh -c myscriptcshअगर यह इसके साथ शुरू होता है #, तो shअन्यथा इसकी व्याख्या करेगा ।

सब सब में, आप यह सुनिश्चित नहीं कर सकते हैं कि उस स्क्रिप्ट की व्याख्या करने के लिए किस शेल का उपयोग किया जाएगा यदि आप नहीं जानते कि यह कैसे और क्या इसे लागू किया जाएगा।

किसी भी स्थिति में, read -pएक-एक bashवाक्य रचना है, इसलिए आप यह सुनिश्चित करना चाहेंगे कि स्क्रिप्ट की व्याख्या की जाए bash(और उस भ्रामक .shविस्तार से बचें )। या तो आप bashनिष्पादन योग्य और उपयोग का मार्ग जानते हैं:

#! /path/to/bash -
read -p ...

या आप का उपयोग करके निष्पादन योग्य (मान स्थापित किया गया है) $PATHकी एक खोज पर भरोसा कर सकते हैं :bashbash

#! /usr/bin/env bash
read -p ...

( envलगभग सर्वव्यापी रूप से पाया जाता है /usr/bin)। वैकल्पिक रूप से, आप इसे POSIX + Bourne संगत बना सकते हैं जिस स्थिति में आप उपयोग कर सकते हैं /bin/sh। सभी प्रणालियों में एक होगा /bin/sh। उनमें से अधिकांश पर यह (अधिकांश भाग के लिए) POSIX- संगत होगा, लेकिन आप इसके बजाय अभी और फिर एक बॉर्न शेल खोज सकते हैं।

#! /bin/sh -
printf >&2 'Enter a user name: '
read user
printf '%s\n' "$user"

1

जब आपके पास कोई #!(जिसे शबंग कहा जाता है ) लाइन नहीं है, तो का उपयोग किया जाता है। यह जांचने के लिए, आप निम्न स्क्रिप्ट चला सकते हैं।

ps -p $$
echo -n "The real shell is: "
realpath /proc/$$/exe

मेरे कंप्यूटर पर मुझे मिलता है

  PID TTY          TIME CMD
13718 pts/16   00:00:00 sh
The real program is: /usr/bin/bash

भले ही मेरा डिफ़ॉल्ट शेल zsh है । यह मेरी मशीन पर bash का उपयोग करता है , sh कमांड को bash द्वारा कार्यान्वित किया जाता है ।


1
आपने ऐसा क्यों किया? कृपया समझाएं या यह बेकार है ...
रोल्स

हेटर्स (मूक अनाम डाउनवोटर्स) नफरत करेंगे। मैंने आपके उत्तर से कुछ सीखा, इसलिए यहाँ एक उत्थान है। :-)
मैक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.