क्या बाश में "और" और "स्रोत" के बीच अंतर है?


37

मैं "के बीच का अंतर ढूंढ रहा था।" और "स्रोत" बिलिन कमांड और कुछ स्रोत (जैसे, इस चर्चा में, और बैश मैनपेज) सुझाव देते हैं कि ये केवल एक ही हैं।

हालांकि, पर्यावरण चर के साथ एक समस्या के बाद, मैंने एक परीक्षण किया। मैंने एक फ़ाइल बनाई testenv.shजिसमें शामिल हैं:

#!/bin/bash
echo $MY_VAR

कमांड प्रॉम्प्ट में, मैंने निम्नलिखित कार्य किया:

> chmod +x testenv.sh
> MY_VAR=12345
> ./testenv.sh

> source testenv.sh
12345
> MY_VAR=12345 ./testenv.sh
12345

[ध्यान दें कि 1 फ़ॉर्म ने एक खाली स्ट्रिंग लौटा दी]

तो, यह थोड़ा प्रयोग का सुझाव है कि है सब के बाद एक अंतर है, जहां "स्रोत" आदेश के लिए, बच्चे पर्यावरण inherits माता-पिता से एक है, जहां के लिए से सभी चर "।" ऐसा नहीं होता।

क्या मुझे कुछ याद आ रहा है, या यह बैश की एक अनिर्दिष्ट / पदावनत विशेषता है ?

[GNU बैश, संस्करण 4.1.5 (1) -release (x86_64-pc-linux-gnu)]

जवाबों:


68

संक्षिप्त जवाब

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

विस्तारित स्पष्टीकरण

यह sourceनिर्मित शेल का सिंटैक्स है, जो वर्तमान शेल में स्क्रिप्ट की सामग्री को निष्पादित करता है (और इस प्रकार वर्तमान शेल के चर के साथ):

source testenv.sh

यह .बिल्ट-इन का सिंटैक्स है, जो sourceनिम्न कार्य करता है :

. testenv.sh

हालाँकि, यह सिंटैक्स स्क्रिप्ट को एक निष्पादन योग्य फ़ाइल के रूप में चलाता है, इसे चलाने के लिए एक नया शेल लॉन्च करता है:

./testenv.sh

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

(बल्कि साथ तुलना नाम से एक फ़ाइल चल रहा के बाद से sourceया .) यह एक नया खोल में चलता है, यह खोल चर के अपने स्वयं के सेट करना होगा। नया शेल कॉलिंग प्रक्रिया से पर्यावरण चर का वारिस करता है (जो कि इस मामले में आपका इंटरेक्टिव शेल है) और वे पर्यावरण चर नए शेल में शेल वेरिएबल बन जाते हैं। हालाँकि, शेल शेल को नए शेल में पारित करने के लिए, निम्नलिखित में से एक होना चाहिए:

  1. शेल चर निर्यात किया गया है, जिससे यह पर्यावरण चर हो सकता है। इसके लिए exportनिर्मित शेल का उपयोग करें। आपके उदाहरण में, आप export MY_VAR=12345चर को एक चरण में सेट और निर्यात करने के लिए उपयोग कर सकते हैं , या यदि यह पहले से ही सेट है तो आप बस उपयोग कर सकते हैं export MY_VAR

  2. शेल वेरिएबल आपके द्वारा चलाए जा रहे कमांड के लिए स्पष्ट रूप से सेट और पास किया गया है, क्योंकि यह कमांड चलने की अवधि के लिए एक पर्यावरण वेरिएबल है। यह आमतौर पर पूरा करता है कि:

    MY_VAR=12345 ./testenv.sh

    यदि MY_VARएक खोल चर है कि निर्यात नहीं किया गया है, तो आप भी चला सकते हैं testenv.shके साथ MY_VARद्वारा एक वातावरण चर के रूप में पारित कर दिया खुद को स्थापित :

    MY_VAR="$MY_VAR" ./testenv.sh

./ लिपियों के लिए सिंटैक्स को काम करने के लिए हैशबैंग लाइन की आवश्यकता होती है (सही ढंग से)

वैसे, कृपया ध्यान दें, जब आप ऊपर के रूप में नाम से एक निष्पादन योग्य को आमंत्रित करते हैं (और निर्मित .या sourceशेल-इन्स के साथ नहीं ), तो इसे चलाने के लिए किस शेल प्रोग्राम का उपयोग किया जाता है यह आमतौर पर निर्धारित नहीं होता है कि आप इसे किस शेल से चला रहे हैं। । बजाय:

  • बाइनरी फ़ाइलों के लिए, कर्नेल को उस विशेष प्रकार की फ़ाइलों को चलाने के लिए कॉन्फ़िगर किया जा सकता है। यह एक "मैजिक नंबर" के लिए फ़ाइल के पहले दो बाइट्स की जांच करता है जो इंगित करता है कि यह किस प्रकार के द्विआधारी निष्पादन योग्य है। यह कैसे निष्पादन योग्य बायनेरिज़ चलाने में सक्षम है।

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

    ( #!पाठ निष्पादन योग्य दर्शाते हुए "मैजिक नंबर" का टेक्स्ट प्रतिनिधित्व है।)

  • उन फ़ाइलों के लिए जिन्हें शेल या अन्य व्याख्या की गई भाषा में चलना चाहिए, पहली पंक्ति इस तरह दिखती है:

    #!/bin/sh

    /bin/shकार्यक्रम को चलाने के लिए जो भी अन्य शेल या दुभाषिया है उसे प्रतिस्थापित किया जा सकता है। उदाहरण के लिए, एक पायथन प्रोग्राम लाइन से शुरू हो सकता है:

    #!/usr/bin/python

    इन पंक्तियों को हैशबंग, शबंग और कई अन्य समान नामों से पुकारा जाता है। इस FOLDOC प्रविष्टि , इस विकिपीडिया लेख और इंटरप्रेटर द्वारा #! / Bin / sh पढ़ा देखें। अधिक जानकारी के लिए।

  • यदि कोई पाठ फ़ाइल निष्पादन योग्य चिह्नित है और आप इसे अपने शेल (जैसे ./filename) से चलाते हैं, लेकिन इसके साथ शुरू नहीं होता है #!, तो कर्नेल इसे निष्पादित करने में विफल रहता है। हालाँकि, यह देखते हुए कि यह हुआ है, आपका शेल इसका नाम कुछ शेल में पास करके इसे चलाने का प्रयास करेगा । वहाँ कुछ आवश्यकताओं को रखा गया है कि शेल क्या है ( "शेल एक शेल को लागू करने के बराबर कमांड निष्पादित करेगा ..." )। व्यवहार में , कुछ गोले - * सहित - खुद का एक और उदाहरण, जबकि अन्य उपयोग करते हैंbash/bin/sh। मैं अत्यधिक सलाह देता हूं कि आप इससे बचें और इसके बजाय एक हैशबैंग लाइन का उपयोग करें (या वांछित दुभाषिया, जैसे, इसे पास करके स्क्रिप्ट चलाएँ bash filename)।

    * GNU बैश मैनुअल , 3.7.2 कमांड खोज और निष्पादन : "यदि यह निष्पादन विफल हो जाता है क्योंकि फ़ाइल निष्पादन योग्य प्रारूप में नहीं है, और फ़ाइल निर्देशिका नहीं है, तो इसे शेल स्क्रिप्ट माना जाता है और शेल इसका वर्णन करता है। में शेल स्क्रिप्ट । "


2
मुझे जो उपयोगी लगा sourceवह यह है कि कार्य बिना किसी लोड या लॉन्च के फिर से शुरू करने के लिए बैश से उपलब्ध हो गए। उदाहरण है #!/bin/bash function olakease {echo olakease;}। एक बार जब आप इसे अपने साथ लोड कर source file.shलेते हैं तो सीधे olakeaseबैश से कॉल कर सकते हैं । वह सहीं मे मुझे पसन्द है। स्रोत निष्पादित करता है तो बहुत सी चीजों को लोड करता है, डॉट .केवल निष्पादन के लिए है और उपयोग की तरह कुछ हैbash file.sh
erm3nda

2
@ erm3nda में .भी यही व्यवहार होता है: . file.shऔर source file.shठीक उसी कार्य को करते हैं, जिसमें परिभाषित कार्यों को बनाए रखना शामिल है file.sh। (शायद आप सोच रहे हैं ./file.sh, जो अलग है। लेकिन यह बिल्टिन का उपयोग नहीं करता है .; इसके बजाय, .पथ का हिस्सा है।)
एलियाह कगन

ओह !, मैंने ध्यान से नहीं पढ़ा। [अंतरिक्ष] फ़ाइल। बहुत बहुत धन्यवाद।
erm3nda

13

हां, आप कुछ याद कर रहे हैं।

मुझे लगता है कि आप 'को भ्रमित कर रहे हैं।' इसका मतलब है कि वर्तमान निर्देशिका, जैसे कि ./testenv.shऔर '।' इसका मतलब है source(जो एक अंतर्निहित कमांड है)। इसलिए मामले में जब '।' इसका मतलब sourceयह होगा . ./testenv.sh। सही बात?

तो यह प्रयास करें:

MY_VAR=12345 
. ./testenv.sh

2
./यह बताता है वह जगह है जहाँ फ़ाइल यह, इसके बिना, बैश पथ के माध्यम से पहली दिखेगा, तो वर्तमान dir कोशिश करता है, तो यह भी नहीं मिला। यदि बैश POSIX मोड में चल रहा है, और आप फ़ाइल (जैसे ./) को कोई पथ प्रदान नहीं करते हैं , तो यह केवल PATH में खोज करेगा, और फ़ाइल को खोजने में विफल होगा यदि वर्तमान dir PATH में नहीं है।
जिरिहा

@geirha हां, आप सही कह रहे हैं, source(और .) वास्तव में $ PATH की पहले जांच करेंगे, भले ही वे वास्तव में सामान्य अर्थ में स्क्रिप्ट नहीं चला रहे हों । मेरी (पूर्व) टिप्पणी गलत थी।
एलियाह कगन

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