"#! / Usr / bin / env bash" और "#! / Usr / bin / bash" में क्या अंतर है?


371

बैश स्क्रिप्ट के हेडर में, उन दो कथनों में क्या अंतर है:

  1. #!/usr/bin/env bash

  2. #!/usr/bin/bash

जब मैंने env मैन पेज पर सलाह ली , तो मुझे यह परिभाषा मिली:

 env - run a program in a modified environment

इसका क्या मतलब है?



6
मुझे कौन बता सकता है कि यह प्रश्न बंद क्यों है, "प्रोग्रामिंग या सॉफ्टवेयर विकास से संबंधित" नहीं है?
तारसाल्लाह

1
मैं मानता हूं कि यह ऑफ-टॉपिक नहीं है, लेकिन यह शायद इस तरह के कई अन्य प्रश्नों का एक डुप्लिकेट है ।
कीथ थॉम्पसन

16
इस प्रश्न को ऑफ-टॉपिक के रूप में चिह्नित नहीं किया जाना चाहिए। इसे "ऑन-टॉपिक" के रूप में चिह्नित करने के लिए 3000 के स्कोर से ऊपर के 5 लोगों की आवश्यकता है और इसे फिर से खोला जा सकता है। यह एक सवाल है - विशेष रूप से प्रोग्रामिंग के बारे में।
Danijel-James W

3
मैं हैरान हूँ। यह पता लगाने के लिए चौंक गया कि लिनक्स डॉक्यूमेंटेशन टेओटोलॉजी के साथ व्याप्त है। xkcd.com/703 git-man-page-generator.lokaltog.net
allyourcode

जवाबों:


323

के माध्यम से एक कमांड चलाने से /usr/bin/envप्रोग्राम के डिफ़ॉल्ट संस्करण में जो कुछ भी है उसे आपके वर्तमान एनवी आयरनमेंट में देखने का लाभ है।

इस तरह, आपको सिस्टम पर एक विशिष्ट स्थान पर देखने की ज़रूरत नहीं है, क्योंकि वे पथ अलग-अलग सिस्टम पर अलग-अलग स्थानों में हो सकते हैं। जब तक यह आपके रास्ते में है, यह इसे खोज लेगा।

एक नकारात्मक पक्ष यह है कि आप एक से अधिक तर्क पारित करने में असमर्थ होंगे (जैसे कि आप लिखने में असमर्थ होंगे /usr/bin/env awk -f) यदि आप लिनक्स का समर्थन करना चाहते हैं, क्योंकि पोसिक्स अस्पष्ट है कि लाइन की व्याख्या कैसे की जाती है, और लिनक्स पहले के बाद सब कुछ व्याख्या करता है। एक भी तर्क निरूपित करने के लिए स्थान। आप इसके चारों ओर पाने /usr/bin/env -Sके envलिए कुछ संस्करणों पर उपयोग कर सकते हैं , लेकिन फिर स्क्रिप्ट कम पोर्टेबल हो जाएगी और हाल ही में सिस्टम पर टूट जाएगी (उदाहरण के लिए Ubuntu 16.04 बाद में नहीं तो)।

एक और नकारात्मक पहलू यह है कि चूंकि आप एक स्पष्ट निष्पादन योग्य फोन नहीं कर रहे हैं, इसलिए यह गलतियों के लिए संभावित है, और बहुउद्देशीय सिस्टम सुरक्षा समस्याओं पर (यदि कोई bashआपके निष्पादन योग्य को अपने पथ में प्राप्त करने में कामयाब रहा , उदाहरण के लिए)।

#!/usr/bin/env bash #lends you some flexibility on different systems
#!/usr/bin/bash     #gives you explicit control on a given system of what executable is called

कुछ स्थितियों में, पहले को प्राथमिकता दी जा सकती है (जैसे कि निष्पादन योग्य लाइन को फिर से काम करने के बिना, अजगर के कई संस्करणों के साथ अजगर स्क्रिप्ट चलाना)। लेकिन उन स्थितियों में जहां सुरक्षा ध्यान केंद्रित है, बाद वाले को प्राथमिकता दी जाएगी, क्योंकि यह कोड इंजेक्शन संभावनाओं को सीमित करता है।


22
एक और दोष यह है कि आप दुभाषिया के लिए एक अतिरिक्त तर्क पारित नहीं कर सकते हैं।
कीथ थॉम्पसन

1
@KeithThompson: गलत जानकारी .. आप / usr / bin / env का उपयोग करके अंतर्निहित दुभाषिया के लिए विकल्प पारित कर सकते हैं!
गौरव अग्रवाल

4
@ गौरव अग्रवाल: मेरे सिस्टम पर नहीं। एक स्क्रिप्ट जिसमें इस एकल पंक्ति को शामिल किया गया है: #!/usr/bin/env echo Helloशिकायत करता है /usr/bin/env: echo Hello: No such file or directory:। जाहिरा तौर पर यह echo Helloएक ही तर्क के रूप में व्यवहार करता है /usr/bin/env
कीथ थॉम्पसन

1
@ AndréLaszlo: envकमांड निश्चित रूप से कमांड को पास करने के लिए तर्क देता है। मुद्दा #!पंक्ति का शब्दार्थ है , और जो कर्नेल पर निर्भर करता है। हाल ही में लिनक्स कर्नेल जैसी चीजों की अनुमति देते हैं #!/usr/bin/env command args, लेकिन पुराने लिनक्स कर्नेल और अन्य सिस्टम नहीं करते हैं।
कीथ थॉम्पसन

1
कोड ब्लॉक में बैकटिक्स क्यों हैं? क्या उन्हें नहीं हटाया जाना चाहिए?
बेंजामिन डब्ल्यू।

63

#!/usr/bin/env NAME$ PATH पर्यावरण चर में NAME के ​​पहले मैच के लिए शेल खोज का उपयोग करता है। यह उपयोगी हो सकता है यदि आप निरपेक्ष पथ के बारे में नहीं जानते हैं या इसके लिए खोज नहीं करना चाहते हैं।


9
कम से कम आपको यह जानना होगा कि एनवी कहां है :)।
at देवमरीबारिस

1
बहुत बढ़िया जवाब। स्पष्ट रूप से बताती है कि env shebang क्या करता है, बजाय यह कहने के कि "आपके सिस्टम कॉन्फ़िगरेशन के आधार पर प्रोग्राम चुनता है"
De Novo

13

/usr/bin/bash/एनवी कमांड के रूप में , दुभाषिया के लिए मार्ग को स्पष्ट रूप से परिभाषित करने के बजाय , दुभाषिया की खोज की जाती है और जहां भी यह पहली बार पाया जाता है, वहां से लॉन्च किया जाता है। इसमें उतार-चढ़ाव दोनों होते हैं


अधिकांश प्रणालियों पर, वे कार्यात्मक रूप से समान होंगे, लेकिन यह आपके बैश और एनवी एंजेबल्स के स्थान पर निर्भर करता है। हालांकि यह सुनिश्चित नहीं है कि यह पर्यावरण चर को कैसे प्रभावित करेगा।
safay

2
"इंटरप्रेटर का उपयोग किए बिना इंटरप्रेटर को निर्दिष्ट करना संभव है। दुभाषिया को पूरा रास्ता देकर। एक समस्या यह है कि अलग-अलग कंप्यूटर सिस्टम पर, सटीक पथ भिन्न हो सकता है। ईएनवी का उपयोग करने के बजाय, दुभाषिया की खोज की जाती है और स्थित होती है। समय जब स्क्रिप्ट चलाया जाता है। यह स्क्रिप्ट को अधिक पोर्टेबल बनाता है, लेकिन यह जोखिम भी बढ़ाता है कि गलत दुभाषिया का चयन किया जाता है क्योंकि यह निष्पादन योग्य खोज पथ पर प्रत्येक निर्देशिका में एक मैच की खोज करता है। यह भी उसी समस्या से ग्रस्त है। एनवी बाइनरी के लिए पथ प्रति-मशीन के आधार पर भी अलग हो सकता है। "- विकिपीडिया
माइक क्लार्क

10

यदि शेल स्क्रिप्ट शुरू होती हैं #!/bin/bash, तो वे हमेशा साथ bashसे चलेंगी /bin। अगर वे फिर भी साथ शुरू #!/usr/bin/env bash, वे के लिए खोज करेंगे bashमें $PATHऔर फिर पहले एक वे प्राप्त कर सकते के साथ शुरू करते हैं।

यह क्यों उपयोगी होगा? मान लें कि आप bashस्क्रिप्ट्स चलाना चाहते हैं, जिसके लिए bash 4.x या नए की आवश्यकता है, फिर भी आपके सिस्टम में केवल bash3.x इंस्टॉल है और वर्तमान में आपका वितरण एक नया संस्करण प्रदान नहीं करता है या आप कोई व्यवस्थापक नहीं हैं और उस सिस्टम पर इंस्टॉल किए गए को परिवर्तित नहीं कर सकते हैं। ।

बेशक, आप bash source कोड डाउनलोड कर सकते हैं और अपने खुद के bash को खरोंच से बना सकते हैं, ~/binउदाहरण के लिए। और आप पहली प्रविष्टि के रूप में शामिल करने के लिए $PATHअपनी .bash_profileफ़ाइल में अपने चर को भी संशोधित कर सकते हैं ~/bin( PATH=$HOME/bin:$PATHजैसा ~कि विस्तार नहीं होगा $PATH)। यदि आप अब कॉल करते हैं bash, तो शेल पहले इसे $PATHक्रम में खोजेगा, इसलिए यह इसके साथ शुरू होता है ~/bin, जहां यह आपकी खोज करेगा bash। अगर स्क्रिप्ट bashका उपयोग करने के लिए खोज होती है, तो एक ही बात होती है #!/usr/bin/env bash, इसलिए ये स्क्रिप्ट अब आपके कस्टम bashबिल्ड का उपयोग करके आपके सिस्टम पर काम करेगी ।

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

इसके साथ सबसे बड़ा नकारात्मक यह envहै कि कुछ सिस्टम केवल एक तर्क की अनुमति देंगे, इसलिए आप ऐसा नहीं कर सकते #!/usr/bin/env <interpreter> <arg>, क्योंकि सिस्टम <interpreter> <arg>एक तर्क के रूप में देखेंगे (वे इसे मानेंगे जैसे कि अभिव्यक्ति उद्धृत की गई थी) और इस प्रकार envनाम की व्याख्या करने वाले की खोज करेंगे <interpreter> <arg>। ध्यान दें कि यह envअपने आप में कमांड की समस्या नहीं है, जो हमेशा कई मापदंडों से गुजरने की अनुमति देता है, लेकिन सिस्टम के शेबंग पार्सर के साथ भी जो कॉल करने से पहले इस लाइन को पार्स करता है env। इस बीच यह अधिकांश प्रणालियों पर तय किया गया है, लेकिन अगर आपकी स्क्रिप्ट अल्ट्रा पोर्टेबल होना चाहती है, तो आप भरोसा नहीं कर सकते कि यह उस सिस्टम पर तय किया गया है जिसे आप चला रहे हैं।

यहां तक ​​कि इसमें सुरक्षा निहितार्थ भी हो सकते हैं, उदाहरण के लिए यदि sudoस्वच्छ वातावरण में कॉन्फ़िगर नहीं किया $PATHगया था या सफाई से बाहर रखा गया था। मुझे इसे प्रदर्शित करें:

आमतौर /binपर एक अच्छी तरह से संरक्षित जगह है, केवल rootवहाँ कुछ भी बदलने में सक्षम है। आपके घर की निर्देशिका, हालांकि, आपके द्वारा चलाया गया कोई भी कार्यक्रम इसमें परिवर्तन करने में सक्षम नहीं है। इसका मतलब है कि दुर्भावनापूर्ण कोड bashकुछ छिपा निर्देशिका में एक नकली जगह ले सकता है , .bash_profileउस निर्देशिका को अपने में शामिल करने के लिए संशोधित कर सकता है $PATH, इसलिए उपयोग करने वाली सभी स्क्रिप्ट #!/usr/bin/env bashउस नकली के साथ चल रही हैं bash। अगर sudoरखता है $PATH, तो आप बड़ी मुसीबत में हैं।

उदाहरण के लिए एक उपकरण ~/.evil/bashनिम्नलिखित सामग्री के साथ एक फ़ाइल बनाता है:

#!/bin/bash

if [ $EUID -eq 0 ]; then
  echo "All your base are belong to us..."
  # We are root - do whatever you want to do
fi

/bin/bash "$@"

चलो एक सरल स्क्रिप्ट बनाते हैं sample.sh:

#!/usr/bin/env bash

echo "Hello World"

अवधारणा का सबूत (एक प्रणाली पर जहाँ sudoरखता है $PATH):

$ ./sample.sh
Hello World

$ sudo ./sample.sh
Hello World

$ export PATH="$HOME/.evil:$PATH"

$ ./sample.sh
Hello World

$ sudo ./sample.sh
All your base are belong to us...
Hello World

आम तौर पर क्लासिक गोले सभी में स्थित होने चाहिए /binऔर यदि आप उन्हें किसी भी कारण से वहां नहीं रखना चाहते हैं, तो यह वास्तव में /binउनके वास्तविक स्थानों (या शायद /binखुद एक सिम्लिंक) को इंगित करने के लिए सिम्लिंक लगाने का मुद्दा नहीं है , इसलिए मैं हमेशा साथ जाता #!/bin/shऔर #!/bin/bash। वहाँ सिर्फ इतना है कि अगर ये अब और काम नहीं करेगा तो टूट जाएगा। ऐसा नहीं है कि POSIX को इन स्थिति की आवश्यकता होगी (POSIX पथ नामों को मानकीकृत नहीं करता है और इस प्रकार यह शेलबैंग फीचर को बिल्कुल भी मानकीकृत नहीं करता है), लेकिन वे इतने सामान्य हैं, कि भले ही कोई सिस्टम एक प्रस्ताव नहीं देगा /bin/sh, यह शायद समझ जाएगा #!/bin/shऔर पता है कि इसके साथ क्या करना है और यह केवल मौजूदा कोड के साथ संगतता के लिए हो सकता है।

लेकिन अधिक आधुनिक, गैर मानक, पर्ल, पीएचपी, पायथन या रूबी जैसे वैकल्पिक दुभाषियों के लिए, यह वास्तव में कहीं भी निर्दिष्ट नहीं है जहां उन्हें स्थित होना चाहिए। वे में हो सकता है /usr/bin, लेकिन वे के रूप में अच्छी में हो सकता है /usr/local/binया एक पूरी तरह से अलग पदानुक्रम शाखा (में /opt/..., /Applications/..., आदि)। यही कारण है कि ये अक्सर #!/usr/bin/env xxxशेबांग सिंटैक्स का उपयोग करते हैं ।


4

मुझे यह उपयोगी लगता है, क्योंकि जब मुझे एनवी के बारे में नहीं पता था, तो स्क्रिप्ट लिखने से पहले मैं यह कर रहा था:

type nodejs > scriptname.js #or any other environment

और फिर मैं फ़ाइल में उस पंक्ति को शबंग में संशोधित कर रहा था।
मैं यह कर रहा था, क्योंकि मुझे हमेशा याद नहीं था कि मेरे कंप्यूटर पर नोडज कहां है - / usr / bin / या / bin /, इसलिए मेरे envलिए बहुत उपयोगी है। शायद इसके साथ विवरण हैं, लेकिन यह मेरा कारण है

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