"#! / Usr / bin / env NAME" का उपयोग "#! / पथ / से / NAME" के बजाय मेरे शबंग के रूप में करना बेहतर क्यों है?


458

मैंने देखा कि कुछ स्क्रिप्ट जो मैंने दूसरों से हासिल की हैं, उनमें शेबंग है #!/path/to/NAMEजबकि अन्य (उसी टूल का उपयोग करते हुए, NAME) में शेलबैंग है #!/usr/bin/env NAME

दोनों ठीक से काम करने लगते हैं। ट्यूटोरियल में (पायथन पर, उदाहरण के लिए), एक सुझाव प्रतीत होता है कि बाद वाला शेबंग बेहतर है। लेकिन, मुझे यह समझ में नहीं आता कि ऐसा क्यों है।

मुझे पता है कि, बाद के शेबंग का उपयोग करने के लिए, NAME को PATH में होना चाहिए, जबकि पहले शेबंग में यह प्रतिबंध नहीं है।

इसके अलावा, यह (मेरे लिए) प्रतीत होता है कि पहला बेहतर शेबंग होगा, क्योंकि यह ठीक उसी जगह पर निर्दिष्ट करता है जहां NAME स्थित है। इसलिए, इस मामले में, अगर NAME (जैसे, / usr / bin / NAME, / usr / local / bin / NAME) के कई संस्करण हैं, तो पहला मामला निर्दिष्ट करता है कि किसका उपयोग करना है।

मेरा सवाल यह है कि पहले शबंग को दूसरे के लिए क्यों पसंद किया जाता है?



@ TheGeeko61: मेरे मामले में मैं कुछ टूट गया था और कुछ चर env में नहीं था। तो मुझे लगता है कि अगर यह सही ढंग से भरी हुई है, तो सत्यापित करने के लिए इस शेबंग का उपयोग करने का सुझाव देता हूं।
गिगामेग्स

जवाबों:


462

यह बेहतर नहीं है जरूरी है।

इसका लाभ #!/usr/bin/env pythonयह है कि यह pythonउपयोगकर्ता में जो भी निष्पादन योग्य प्रतीत होता है उसका उपयोग करेगा $PATH

नुकसान की #!/usr/bin/env pythonहै कि यह प्रयोग करेंगे जो कुछ भी है pythonनिष्पादन योग्य उपयोगकर्ता के दशक में पहली बार प्रकट होता $PATH

इसका मतलब है कि स्क्रिप्ट अलग तरीके से व्यवहार कर सकती है जो इस बात पर निर्भर करती है कि इसे कौन चलाता है। एक उपयोगकर्ता के लिए, यह /usr/bin/pythonओएस के साथ स्थापित किया गया उपयोग कर सकता है । दूसरे के लिए, यह एक प्रयोगात्मक का उपयोग कर सकता है जो /home/phred/bin/pythonसही ढंग से काम नहीं करता है।

और अगर pythonकेवल में स्थापित किया गया है /usr/local/bin, यदि कोई उपयोगकर्ता नहीं है /usr/local/binमें $PATHभी स्क्रिप्ट चलाने के लिए सक्षम नहीं होगा। (यह शायद आधुनिक प्रणालियों पर बहुत अधिक संभावना नहीं है, लेकिन यह अधिक अस्पष्ट दुभाषिया के लिए आसानी से हो सकता है।)

यह निर्दिष्ट करके कि #!/usr/bin/pythonआप किसी विशेष प्रणाली पर स्क्रिप्ट को चलाने के लिए कौन से दुभाषिया का उपयोग करेंगे ।

एक अन्य संभावित समस्या यह है कि यह #!/usr/bin/envट्रिक आपको इंट्रप्टर (स्क्रिप्ट के नाम के अलावा, जो अंतर्निहित रूप से पारित हो जाता है) के लिए तर्क पारित करने की अनुमति नहीं देता है । यह आमतौर पर एक मुद्दा नहीं है, लेकिन यह हो सकता है। कई पर्ल स्क्रिप्ट के साथ लिखा गया है #!/usr/bin/perl -w, लेकिन use warnings;इन दिनों अनुशंसित प्रतिस्थापन है। Csh लिपियों का उपयोग करना चाहिए #!/bin/csh -f- लेकिन csh लिपियों की सिफारिश पहले नहीं की जाती है। लेकिन इसके अन्य उदाहरण हो सकते हैं।

मेरे पास एक व्यक्तिगत स्रोत नियंत्रण प्रणाली में कई पर्ल स्क्रिप्ट हैं जिन्हें मैं एक नई प्रणाली पर एक खाता स्थापित करते समय स्थापित करता हूं। मैं एक इंस्टॉलर स्क्रिप्ट का उपयोग करता हूं जो #!प्रत्येक स्क्रिप्ट की लाइन को संशोधित करता है क्योंकि यह इसे मेरे में स्थापित करता है $HOME/bin। (मुझे #!/usr/bin/perlहाल ही में इसके अलावा किसी भी चीज़ का उपयोग नहीं करना पड़ा है ; यह तब तक वापस चला जाता है जब पर्ल अक्सर डिफ़ॉल्ट रूप से स्थापित नहीं होता था।)

एक मामूली बिंदु: #!/usr/bin/envचाल यकीनन envकमांड का दुरुपयोग है , जो मूल रूप से इरादा था (जैसा कि नाम से पता चलता है) एक परिवर्तित वातावरण के साथ एक कमांड लागू करने के लिए। इसके अलावा, कुछ पुराने सिस्टम (SunOS 4 सहित, अगर मुझे सही से याद है) में envकमांड नहीं थी /usr/bin। न तो इनमें से एक महत्वपूर्ण चिंता का विषय है। envइस तरह से काम करता है, बहुत सारी स्क्रिप्ट #!/usr/bin/envचाल का उपयोग करती हैं , और ओएस प्रदाताओं को इसे तोड़ने के लिए कुछ भी करने की संभावना नहीं है। यह एक समस्या हो सकती है यदि आप चाहते हैं कि आपकी स्क्रिप्ट वास्तव में पुरानी प्रणाली पर चले, लेकिन तब आपको इसे फिर से संशोधित करने की आवश्यकता होगी।

एक अन्य संभावित मुद्दा, (टिप्पणी में इसे इंगित करने के लिए सोपालजो डे एरियेरेज़ का धन्यवाद) यह है कि क्रोन नौकरियां एक प्रतिबंधित वातावरण के साथ चलती हैं। विशेष रूप से, $PATHआमतौर पर ऐसा कुछ होता है /usr/bin:/bin। इसलिए अगर इंटरप्रेटर वाली निर्देशिका उन निर्देशिकाओं में से एक में नहीं होती है, भले ही वह $PATHउपयोगकर्ता शेल में आपके डिफ़ॉल्ट में हो, तो यह /usr/bin/envट्रिक काम नहीं करने वाली है। आप सटीक पथ निर्दिष्ट कर सकते हैं, या आप $PATH( man 5 crontabविवरण के लिए) सेट करने के लिए अपने कॉन्ट्राब में एक रेखा जोड़ सकते हैं ।


4
यदि / usr / bin / perl perl 5.8 है, तो $ HOME / bin / perl 5.12 है, और स्क्रिप्ट में 5.12 हार्डकोड / usr / bin / perl की आवश्यकता है, यह स्क्रिप्ट को चलाने के लिए एक बड़ा दर्द हो सकता है। मैंने शायद ही कभी देखा है कि पीएटीएच से usr / bin / env perl Grab perl होना एक समस्या है, लेकिन यह अक्सर बहुत मददगार होता है। और यह एक्जीक्यूट हैक की तुलना में बहुत पहले से है!
विलियम पर्ससेल

8
यह ध्यान देने योग्य है, यदि आप एक विशिष्ट दुभाषिया संस्करण का उपयोग करना चाहते हैं, तो / usr / bin / env अभी भी बेहतर है। सिर्फ इसलिए कि आमतौर पर आपके मशीन पर perl5, perl5.12, perl5.10, python3.3, python3.32, आदि नाम से कई इंटरप्रेटर संस्करण इंस्टॉल किए जाते हैं और यदि आपका ऐप केवल उस विशिष्ट संस्करण पर परीक्षण किया गया है, तो आप अभी भी निर्दिष्ट कर सकते हैं। #! / usr / bin / env perl5.12 और ठीक है, भले ही उपयोगकर्ता ने इसे कहीं असामान्य स्थापित किया हो। मेरे अनुभव में, 'पायथन' आमतौर पर सिस्टम मानक संस्करण के लिए एक सिम्लिंक है (जरूरी नहीं कि सिस्टम पर सबसे हाल का संस्करण)।
जड़

6
@ बरोट: पर्ल के लिए, उस उद्देश्य में से कुछuse v5.12; कार्य करता है । और असफल हो जाएगा अगर सिस्टम में पर्ल 5.14 है लेकिन 5.12 नहीं है। पायथन 2 बनाम 3 के लिए, और काम करने की संभावना है। #!/usr/bin/env perl5.12#!/usr/bin/python2#!/usr/bin/python3
कीथ थॉम्पसन

3
@GoodPerson: मान लीजिए कि मैं एक पर्ल स्क्रिप्ट लिखता हूं जिसे इंस्टॉल किया जाना है /usr/local/bin। मुझे पता है कि यह सही तरीके से काम करता है /usr/bin/perl। मुझे नहीं पता कि क्या यह perlनिष्पादन योग्य के साथ काम करता है जो कुछ यादृच्छिक उपयोगकर्ता के पास होता है $PATH। शायद कोई पर्ल के किसी प्राचीन संस्करण के साथ प्रयोग कर रहा है; क्योंकि मैंने निर्दिष्ट किया है #!/usr/bin/perl, मेरी स्क्रिप्ट (जिसे उपयोगकर्ता को आवश्यक रूप से पता भी नहीं है या देखभाल एक पर्ल स्क्रिप्ट है) काम करना बंद नहीं करेगी।
कीथ थॉम्पसन

5
यदि यह साथ काम नहीं करता है /usr/bin/perl, तो मुझे बहुत जल्दी पता चल जाएगा, और इसे रखने के लिए सिस्टम मालिक / व्यवस्थापक की जिम्मेदारी है। यदि आप मेरी स्क्रिप्ट को अपने स्वयं के पर्ल के साथ चलाना चाहते हैं, तो बेझिझक एक कॉपी को पकड़ो और संशोधित करें या इसके माध्यम से इनवाइट करें perl foo। (और आप इस संभावना पर विचार कर सकते हैं कि जिन 55 लोगों ने इस उत्तर को उकसाया है, वे भी एक या दो ही जानते हैं। यह निश्चित रूप से संभव है कि आप सही हों और वे सभी गलत हों, लेकिन मैं जिस तरह से दांव लगाऊंगा वह नहीं है।)
कीथ थॉम्पसन

101

क्योंकि / usr / bin / env आपकी व्याख्या कर सकता है $PATH, जो स्क्रिप्ट को अधिक पोर्टेबल बनाता है।

#!/usr/local/bin/python

क्या केवल आपकी स्क्रिप्ट चलेगी यदि अजगर / usr / स्थानीय / बिन में स्थापित है।

#!/usr/bin/env python

आपकी व्याख्या करेगा $PATH, और आपके किसी भी निर्देशिका में अजगर को ढूंढेगा $PATH

तो आपकी स्क्रिप्ट अधिक पोर्टेबल है, और उन प्रणालियों पर संशोधन के बिना काम करेगी जहां अजगर को स्थापित किया गया है /usr/bin/python, या /usr/local/bin/python, या कस्टम निर्देशिकाओं (जो इसमें जोड़ा गया है $PATH), जैसे /opt/local/bin/python

पोर्टेबिलिटी एकमात्र कारण है जिसका उपयोग envकरना कठिन कोडित पथों को पसंद किया जाता है।


19
pythonनिष्पादन में virtualenvवृद्धि के लिए कस्टम निर्देशिकाएँ विशेष रूप से सामान्य हैं क्योंकि उपयोग बढ़ता है।
Xiong Chiamiov

1
किस बारे में #! python, इसका उपयोग क्यों नहीं किया जाता है?
kristianp

6
#! pythonउपयोग नहीं किया जाता है क्योंकि आपको अजगर के बाइनरी के समान निर्देशिका में होना चाहिए, क्योंकि नंगे pythonको फ़ाइल के पूर्ण पथ के रूप में व्याख्या किया गया है। यदि आपके पास वर्तमान निर्देशिका में एक अजगर बाइनरी नहीं है, तो आपको एक त्रुटि मिलेगी bash: ./script.py: python: bad interpreter: No such file or directory। यह वैसा ही है जैसा आपने प्रयोग किया था#! /not/a/real/path/python
टिम कैनेडी

47

निरपेक्ष पथ को निर्दिष्ट करना किसी दिए गए सिस्टम पर अधिक सटीक है। नकारात्मक पक्ष यह है कि यह बहुत सटीक है। मान लीजिए कि आपको एहसास है कि पर्ल की सिस्टम इंस्टॉलेशन आपकी स्क्रिप्ट्स के लिए बहुत पुरानी है और आप इसके बजाय खुद का उपयोग करना चाहते हैं: तो आपको स्क्रिप्ट्स को एडिट करना होगा और बदलना #!/usr/bin/perlहोगा #!/home/myname/bin/perl। इससे भी बदतर, यदि आपके पास /usr/binकुछ मशीनों में पर्ल , /usr/local/binदूसरों पर, और /home/myname/bin/perlअन्य मशीनों पर हैं, तो आपको स्क्रिप्ट की तीन अलग-अलग प्रतियां बनाए रखनी होंगी और प्रत्येक मशीन पर उपयुक्त एक को निष्पादित करना होगा।

#!/usr/bin/envअगर PATHबुरा है, तो टूट जाता है, लेकिन लगभग कुछ भी नहीं करता है। एक बुरे के साथ काम करने का प्रयास करना PATHबहुत ही कम उपयोगी है, और यह दर्शाता है कि आप जिस सिस्टम पर स्क्रिप्ट चला रहे हैं, उसके बारे में बहुत कम जानते हैं, इसलिए आप किसी भी पूर्ण पथ पर भरोसा नहीं कर सकते।

दो कार्यक्रम हैं जिनके स्थान पर आप लगभग हर यूनिक्स संस्करण पर भरोसा कर सकते हैं: /bin/shऔर /usr/bin/env। कुछ अस्पष्ट और ज्यादातर सेवानिवृत्त यूनिक्स वेरिएंट के पास /bin/envबिना थे /usr/bin/env, लेकिन आप उनका सामना करने की संभावना नहीं रखते हैं। आधुनिक व्यवस्थाओं का /usr/bin/envठीक उसी प्रकार से है, क्योंकि इसके बड़े पैमाने पर उपयोग में आने वाले शेबंग हैं। /usr/bin/envकुछ ऐसा है जिस पर आप भरोसा कर सकते हैं।

इसके अलावा /bin/sh, केवल एक बार जब आप एक स्क्रिप्ट में पूर्ण पथ का उपयोग करना चाहिए जब आपकी स्क्रिप्ट पोर्टेबल होने का मतलब नहीं है, तो आप दुभाषिया के लिए एक ज्ञात स्थान पर भरोसा कर सकते हैं। उदाहरण के लिए, एक बैश स्क्रिप्ट जो केवल लिनक्स पर काम करती है सुरक्षित रूप से उपयोग कर सकती है #!/bin/bash। एक स्क्रिप्ट जो केवल घर में उपयोग करने के लिए होती है, वह घर दुभाषिया स्थान सम्मेलनों पर भरोसा कर सकती है।

#!/usr/bin/envडाउनसाइड होता है। यह एक निरपेक्ष पथ को निर्दिष्ट करने की तुलना में अधिक लचीला है लेकिन फिर भी दुभाषिया नाम को जानना आवश्यक है। कभी-कभी आप एक दुभाषिया को चलाना चाहते हैं $PATH, जो स्क्रिप्ट के सापेक्ष किसी स्थान पर नहीं हो। ऐसे मामलों में, आप अक्सर एक पॉलीग्लॉट स्क्रिप्ट बना सकते हैं, जिसकी व्याख्या मानक शेल और आपके वांछित दुभाषिया द्वारा दोनों की जा सकती है। उदाहरण के लिए, पायथन 2 स्क्रिप्ट को पोर्टेबल बनाने के लिए दोनों प्रणालियों के लिए जहां pythonपायथन 3 है और python2पायथन 2 है, और उन प्रणालियों के लिए जहां pythonपायथन 2 है और python2मौजूद नहीं है:

#!/bin/sh
''':'
if type python2 >/dev/null 2>/dev/null; then
  exec python2 "$0" "$@"
else
  exec python "$0" "$@"
fi
'''
# real Python script starts here
def …

22

विशेष रूप से पर्ल के लिए, #!/usr/bin/envदो कारणों से खराब विचार है।

पहला, यह पोर्टेबल नहीं है। कुछ अस्पष्ट प्लेटफार्मों पर env in / usr / bin नहीं है। दूसरा, जैसा कि कीथ थॉम्पसन ने उल्लेख किया है, यह शेबंग लाइन पर तर्क पारित करने में परेशानी पैदा कर सकता है। अधिकतम पोर्टेबल समाधान यह है:

#!/bin/sh
exec perl -x "$0" "$@"
#!perl

यह कैसे काम करता है, इसके विवरण के लिए, 'perldoc perlrun' देखें और -x तर्क के बारे में यह क्या कहता है।


वास्तव में aser मैं देख रहा था: पर्ल स्क्रिप्ट के लिए पोरेबल "शेबंग" कैसे लिखा जाए जो पर्ल को पास करने के लिए अतिरिक्त अभिलेखों को पारित करने की अनुमति देगा (आपके उदाहरण में अंतिम पंक्ति अतिरिक्त अभिलेखों को स्वीकार करता है)।
अमोखुइगन्सन

15

दोनों के बीच अंतर होने का कारण यह है कि लिपियों को कैसे निष्पादित किया जाता है।

का उपयोग करना /usr/bin/env(जो, जैसा कि अन्य उत्तरों में उल्लेख किया गया है, /usr/binकुछ OSes में नहीं है ) की आवश्यकता है, क्योंकि आप इसके बाद एक निष्पादन योग्य नाम नहीं डाल सकते हैं #!- यह एक पूर्ण पथ होना चाहिए। ऐसा इसलिए है क्योंकि #!तंत्र शेल की तुलना में निचले स्तर पर काम करता है। यह कर्नेल के बाइनरी लोडर का हिस्सा है। इसका परीक्षण किया जा सकता है। इसे एक फ़ाइल में रखें और इसे निष्पादन योग्य चिह्नित करें:

#!bash

echo 'foo'

जब आप इसे चलाने का प्रयास करेंगे तो आपको यह एक त्रुटि के समान दिखाई देगा:

Failed to execute process './test.sh'. Reason:
The file './test.sh' does not exist or could not be executed.

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


11

उपयोग करने के साथ दो और समस्याएं हैं #!/usr/bin/env

  1. यह दुभाषिया के लिए पूर्ण पथ निर्दिष्ट करने की समस्या को हल नहीं करता है, यह बस इसे स्थानांतरित करता है env

    envकोई और अधिक में होने की गारंटी है /usr/bin/envकी तुलना bashमें होने की गारंटी है /bin/bashमें या अजगर /usr/bin/python

  2. env ARGV [0] को दुभाषिया (e..g bash या python) के नाम से अधिलेखित किया गया है।

    यह आपकी स्क्रिप्ट के नाम को प्रदर्शित होने से रोकता है, उदाहरण के लिए, psआउटपुट (या यह कैसे / कहाँ प्रकट होता है) बदलता है और इसे इसके साथ खोजना असंभव बनाता है, जैसे;ps -C scriptname.sh

[अपडेट २०१६-०६-०४]

और एक तीसरी समस्या:

  1. अपने PATH को बदलना किसी स्क्रिप्ट की पहली पंक्ति को संपादित करने की तुलना में अधिक काम करता है, विशेषकर जब ऐसे संपादन स्क्रिप्टिंग तुच्छ हो। उदाहरण के लिए:

    printf "%s\n" 1 i '#!'$(type -P python2) . w | ed foo.py

    $ PATH के लिए एक निर्देशिका को पूर्व-लंबित या पूर्व-लंबित करना काफी आसान है (हालाँकि आपको अभी भी इसे स्थायी बनाने के लिए एक फ़ाइल संपादित करनी है - आपकी ~/.profileया जो भी - और यह स्क्रिप्ट से आसान है, क्योंकि PATH स्क्रिप्ट में कहीं भी सेट की जा सकती है। , पहली पंक्ति में नहीं)।

    पथ निर्देशिकाओं के क्रम को बदलना काफी अधिक कठिन है .... और सिर्फ #!पंक्ति को संपादित करने की तुलना में कहीं अधिक कठिन है ।

    और आपके पास अभी भी अन्य सभी समस्याएं हैं जिनका उपयोग करना #!/usr/bin/envआपको देता है।

    @jlliagre एक टिप्पणी में सुझाव देता है जो #!/usr/bin/envआपकी स्क्रिप्ट को कई दुभाषिया संस्करणों के साथ परीक्षण करने के लिए उपयोगी है, "केवल उनके पेट / पाथ क्रम को बदलकर"

    यदि आपको ऐसा करने की आवश्यकता है, तो #!आपकी स्क्रिप्ट के शीर्ष पर बस कई पंक्तियों का होना बहुत आसान है (वे अभी कहीं भी टिप्पणियां हैं लेकिन बहुत पहली पंक्ति हैं) और जिसको आप अभी उपयोग करना चाहते हैं उसे काट / कॉपी-पेस्ट करें पहली पंक्ति।

    में vi, कि करने के लिए कर्सर को ले के रूप में सरल किया जाएगा #!, लाइन आप चाहते हैं तो टाइपिंग dd1GPया Y1GP। यहां तक ​​कि एक संपादक के रूप में भी nano, यह माउस को कॉपी और पेस्ट करने के लिए सेकंड का समय लेगा।


कुल मिलाकर, उपयोग करने के फायदे #!/usr/bin/envकम से कम सर्वोत्तम हैं, और निश्चित रूप से नुकसान को पछाड़ने के करीब भी नहीं आते हैं। यहां तक ​​कि "सुविधा" का लाभ काफी हद तक भ्रम है।

IMO, यह एक ख़ास तरह के प्रोग्रामर द्वारा प्रचारित एक मूर्खतापूर्ण विचार है, जो सोचता है कि ऑपरेटिंग सिस्टम के साथ काम करने के लिए कुछ नहीं है, वे एक समस्या है जिसके चारों ओर काम किया जाना है (या सर्वोत्तम पर ध्यान नहीं दिया गया)।

पुनश्च: यहाँ एक से अधिक फ़ाइलों की व्याख्या करने के लिए एक सरल स्क्रिप्ट दी गई है।

change-shebang.sh:

#!/bin/bash

interpreter="$1"
shift

if [ -z "$(type -P $interpreter)" ] ; then
  echo "Error: '$interpreter' is not executable." >&2
  exit 1
fi

if [ ! -d "$interpreter" ] && [ -x "$interpreter" ] ; then
  shebang='#!'"$(realpath -e $interpreter)" || exit 1
else
  shebang='#!'"$(type -P $interpreter)"
fi

for f in "$@" ; do
  printf "%s\n" 1 i "$shebang" . w | ed "$f"
done

जैसे, change-shebang.sh python2.7 *.pyया , इसे चलाएंchange-shebang.sh $HOME/bin/my-experimental-ruby *.rb


4
यहां किसी और ने ARGV [0] समस्या का उल्लेख नहीं किया है। और किसी ने भी इस तरह से / पथ / से / एनवी मुद्दे का उल्लेख नहीं किया है जो सीधे इसका उपयोग करने के लिए एक तर्क को संबोधित करता है (यानी कि एक अप्रत्याशित स्थान में बैश या पर्ल हो सकता है)।
कास

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

3
गैर- sysadmins अपने sysadmin को ऐसा करने के लिए कह सकते हैं। या वे बस स्क्रिप्ट को संपादित कर सकते हैं और #!लाइन बदल सकते हैं ।
कैस

2
ठीक यही है कि env बचने के लिए मदद कर रहा है: एक sysadmin या OS विशिष्ट तकनीकी ज्ञान पर निर्भर करता है जो अजगर या उससे संबंधित नहीं है।
जूलियाग्रे

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

8

यहाँ एक और उदाहरण जोड़ना:

उपयोग करना envतब भी उपयोगी होता है जब आप rvmउदाहरण के लिए कई वातावरणों के बीच स्क्रिप्ट साझा करना चाहते हैं ।

इसे cmd लाइन पर चलाने से पता चलता है कि #!/usr/bin/env rubyस्क्रिप्ट के अंदर उपयोग किए जाने पर कौन से रूबी संस्करण का उपयोग किया जाएगा :

env ruby --version

इसलिए, जब आप उपयोग करते हैं env, तो आप अपनी स्क्रिप्ट को बदलने के बिना, rvm के माध्यम से विभिन्न रूबी संस्करणों का उपयोग कर सकते हैं।


1
// , उत्कृष्ट विचार। कई दुभाषियों का पूरा बिंदु कोड को तोड़ना नहीं है, या कोड को उस विशिष्ट दुभाषिया पर निर्भर करना है
नाथन बसानी

4

यदि आप अपने लिए या अपनी नौकरी के लिए विशुद्ध रूप से लिख रहे हैं और आपके द्वारा कॉल किए जा रहे दुभाषिया का स्थान हमेशा एक ही स्थान पर है, तो सभी तरीकों से सीधे रास्ते का उपयोग करें। अन्य सभी मामलों में उपयोग करें #!/usr/bin/env

यहाँ क्यों है: आपकी स्थिति में pythonदुभाषिया एक ही स्थान पर था चाहे आप किस वाक्य-विन्यास का उपयोग करते हों, लेकिन कई लोगों के लिए यह एक अलग स्थान पर स्थापित हो सकता है। हालांकि अधिकांश प्रमुख प्रोग्रामिंग दुभाषिए /usr/bin/बहुत से नए सॉफ़्टवेयर में स्थित हैं, जो कि डिफ़ॉल्ट है /usr/local/bin/

मैं भी हमेशा उपयोग करने का तर्क दूंगा #!/usr/bin/envक्योंकि अगर आपके पास एक ही दुभाषिया के कई संस्करण स्थापित हैं और आपको नहीं पता कि आपका शेल क्या डिफ़ॉल्ट होगा, तो आपको शायद इसे ठीक करना चाहिए।


5
"अन्य सभी मामलों में # का उपयोग करें! / Usr / bin / env" बहुत मजबूत है। // जैसा कि @KeithThompson और अन्य बताते हैं, #! / Usr / bin / env का अर्थ है कि स्क्रिप्ट किस तरह / कैसे चलती है, इसके आधार पर अलग-अलग व्यवहार कर सकते हैं। कभी-कभी यह अलग व्यवहार एक सुरक्षा बग हो सकता है। // उदाहरण के लिए, सेवरिड या सेटगिड स्क्रिप्ट के लिए "#! / Usr / bin / env python" का उपयोग न करें, क्योंकि स्क्रिप्ट का उपयोग करने वाला उपयोगकर्ता PATH में "अजगर" नामक फ़ाइल में मैलवेयर रख सकता है। सेतुबंध / gid स्क्रिप्ट कभी भी एक अच्छा विचार है एक अलग मुद्दा है - लेकिन निश्चित रूप से, कोई भी setuid / gid निष्पादन योग्य कभी भी उपयोगकर्ता द्वारा प्रदान किए गए वातावरण पर भरोसा नहीं करना चाहिए।
क्रेजी ग्लीव

@KrazyGlew, आप लिनक्स पर एक स्क्रिप्ट सेट नहीं कर सकते। आप इसे एक निष्पादन योग्य गर्त करते हैं। और इस निष्पादन योग्य को लिखते समय, पर्यावरण चर को साफ करने के लिए यह अच्छा अभ्यास है, और व्यापक रूप से किया जाता है। कुछ पर्यावरण चर को उद्देश्यपूर्ण रूप से अनदेखा किया जाता है
MayeulC

3

पोर्टेबिलिटी और कॉम्पिटिबिलिटी कारणों से इसका उपयोग करना बेहतर है

#!/usr/bin/env bash

के बजाय

#!/usr/bin/bash

मल्टीपल ऑक्यूपायडिटी हैं, जहां एक बाइनरी लिनक्स / यूनिक्स सिस्टम पर स्थित हो सकता है। फ़ाइल सिस्टम पदानुक्रम के विस्तृत विवरण के लिए hier (7) मैनपेज की जाँच करें।

उदाहरण के लिए FreeBSD सभी सॉफ्टवेयर स्थापित करता है, जो आधार प्रणाली का हिस्सा नहीं है, / usr / लोकल / में । चूंकि बैश बेस सिस्टम का हिस्सा नहीं है, इसलिए बैश बाइनरी को / usr / लोकल / बिन / बैश में स्थापित किया जाता है ।

जब आप एक पोर्टेबल बैश / csh / perl / जो भी स्क्रिप्ट चाहते हैं, जो कि अधिकांश लिनक्स डिस्ट्रीब्यूशन और FreeBSD के अंतर्गत आता है, तो आपको #! / Usr / bin / env का उपयोग करना चाहिए ।

यह भी ध्यान दें, कि अधिकांश लिनक्स इंस्टॉलेशन ने भी (हार्ड) env बाइनरी को / bin / env या सॉफ्टलिंक / usr / bin से / bin में लिंक किया है, जिसे शेबंग में उपयोग नहीं किया जाना चाहिए । इसलिए #! / Bin / env का उपयोग न करें ।

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