एकमात्र मुख्य अंतर किसी स्क्रिप्ट के सोर्सिंग और निष्पादन के बीच है। source foo.shइसे स्रोत करेगा और आपके द्वारा दिखाए जाने वाले अन्य सभी उदाहरण निष्पादित कर रहे हैं। विस्तृत रूप में:
./file.sh
यह file.shउस स्क्रिप्ट को निष्पादित करेगा जिसे वर्तमान निर्देशिका में है ( ./)। आम तौर पर, जब आप दौड़ते हैं command, तो शेल आपके $PATHद्वारा निष्पादन योग्य फ़ाइल नामक निर्देशिका के माध्यम से दिखेगा command। यदि आप पूर्ण पथ देते हैं, जैसे कि /usr/bin/commandया ./command, तो $PATHअनदेखा किया जाता है और उस विशिष्ट फ़ाइल को निष्पादित किया जाता है।
../file.sh
यह मूल रूप से ./file.shसिवाय इसके कि वर्तमान निर्देशिका में देखने के बजाय file.sh, मूल निर्देशिका ( ../) में दिख रही है ।
sh file.sh
इसके समतुल्य sh ./file.sh, ऊपर के रूप file.shमें यह वर्तमान निर्देशिका में कहे जाने वाले स्क्रिप्ट को चलाएगा । अंतर यह है कि आप इसे shखोल के साथ स्पष्ट रूप से चला रहे हैं । उबंटू सिस्टम पर, वह है dashऔर नहीं bash। आमतौर पर, लिपियों में एक शबंग रेखा होती है जो उस कार्यक्रम को देती है जिसे उन्हें चलाया जाना चाहिए। एक अलग के साथ उन्हें बुला ओवरराइड करता है। उदाहरण के लिए:
$ cat foo.sh
#!/bin/bash
## The above is the shebang line, it points to bash
ps h -p $$ -o args='' | cut -f1 -d' ' ## This will print the name of the shell
वह स्क्रिप्ट बस इसे चलाने के लिए उपयोग किए गए शेल के नाम को प्रिंट करेगी। आइए देखें कि अलग-अलग तरीकों से क्या कहा जाता है:
$ bash foo.sh
bash
$ sh foo.sh
sh
$ zsh foo.sh
zsh
तो, एक स्क्रिप्ट को कॉल करने के साथ shell scriptशेबंग लाइन (यदि मौजूद है) को ओवरराइड करेंगे और जो भी शेल आप इसे बताएंगे, उसके साथ स्क्रिप्ट को चलाएं।
source file.sh या . file.sh
इसे, आश्चर्यजनक रूप से पर्याप्त, स्क्रिप्ट सोर्सिंग कहा जाता है । कीवर्ड sourceशेल अंतर्निहित .कमांड के लिए एक अन्य नाम है । यह वर्तमान शेल के भीतर स्क्रिप्ट को निष्पादित करने का एक तरीका है। आम तौर पर, जब किसी स्क्रिप्ट को निष्पादित किया जाता है, तो इसे अपने स्वयं के शेल में चलाया जाता है जो वर्तमान की तुलना में अलग है। उदाहरण देकर स्पष्ट करने के लिए:
$ cat foo.sh
#!/bin/bash
foo="Script"
echo "Foo (script) is $foo"
अब, अगर मैं fooपैरेंट शेल में कुछ और के लिए चर सेट करता हूं और फिर स्क्रिप्ट चलाता है, तो स्क्रिप्ट एक अलग मान प्रिंट करेगी foo(क्योंकि यह स्क्रिप्ट के भीतर भी सेट है) लेकिन fooमूल शेल में मान अपरिवर्तित रहेगा:
$ foo="Parent"
$ bash foo.sh
Foo (script) is Script ## This is the value from the script's shell
$ echo "$foo"
Parent ## The value in the parent shell is unchanged
हालांकि, अगर मैं स्क्रिप्ट को निष्पादित करने के बजाय स्रोत करता हूं, तो इसे एक ही शेल में चलाया जाएगा, ताकि fooअभिभावक का मान बदल जाए:
$ source ./foo.sh
Foo (script) is Script ## The script's foo
$ echo "$foo"
Script ## Because the script was sourced,
## the value in the parent shell has changed
इसलिए, सोर्सिंग का उपयोग उन कुछ मामलों में किया जाता है जहां आप उस स्क्रिप्ट को प्रभावित करना चाहते हैं जिसे आप इसे चला रहे हैं। यह आमतौर पर शेल वेरिएबल्स को परिभाषित करने के लिए उपयोग किया जाता है और स्क्रिप्ट खत्म होने के बाद उन्हें उपलब्ध होता है।
उस सब को ध्यान में रखते हुए, आपको अलग-अलग उत्तर मिलने का कारण है, सबसे पहले, यह कि आपकी स्क्रिप्ट वह नहीं करती है जो आप सोचते हैं कि वह करता है। यह उस समय की संख्या को गिनता bashहै जो आउटपुट में दिखाई देता है ps। यह खुले टर्मिनलों की संख्या नहीं है , यह चल रहे गोले की संख्या है (वास्तव में, यह भी नहीं है, लेकिन यह एक और चर्चा है)। स्पष्ट करने के लिए, मैंने आपकी स्क्रिप्ट को थोड़ा सरल किया:
#!/bin/bash
logname=terdon
not=`ps -au$logname | grep -c bash`
echo "The number of shells opened by $logname is $not"
और इसे केवल एक ही टर्मिनल ओपन के साथ विभिन्न तरीकों से चलाएं:
डायरेक्ट लॉन्चिंग ./foo.sh,।
$ ./foo.sh
The number of shells opened by terdon is 1
यहाँ, आप शेबंग लाइन का उपयोग कर रहे हैं। इसका मतलब यह है कि स्क्रिप्ट को वहां जो भी सेट किया गया है, उसके द्वारा सीधे निष्पादित किया जाता है। यह उस तरह से प्रभावित करता है जिस तरह से स्क्रिप्ट को आउटपुट में दिखाया गया है ps। के रूप में सूचीबद्ध होने के बजाय bash foo.sh, यह केवल उसी रूप में दिखाया जाएगा foo.shजिसका अर्थ है कि आपका grepइसे याद करेगा। वास्तव में 3 बैश इंस्टेंस चल रहे हैं: मूल प्रक्रिया, स्क्रिप्ट चलाने वाली बैश और एक अन्य जो psकमांड चलाता है । यह अंतिम महत्वपूर्ण है, कमांड प्रतिस्थापन ( `command`या $(command)) के साथ एक कमांड लॉन्च करने के परिणामस्वरूप मूल शेल की एक प्रति लॉन्च की जा रही है और यह कमांड चलाता है। यहाँ, हालाँकि, इनमें से कोई भी इस तरह नहीं दिखाया गया है कि psइसका उत्पादन किस तरह से दिखाया गया है ।
स्पष्ट (बाश) खोल के साथ सीधा प्रक्षेपण
$ bash foo.sh
The number of shells opened by terdon is 3
यहाँ, क्योंकि आप के साथ चल रहे हैं bash foo.sh, का उत्पादन psदिखाएगा bash foo.shऔर गिना जाएगा। इसलिए, यहां हमारे पास मूल प्रक्रिया है, bashस्क्रिप्ट चलाने और क्लोन किए गए शेल (चल रहे हैं ps) सभी को दिखाया गया है क्योंकि अब psउनमें से प्रत्येक दिखाएगा क्योंकि आपकी कमांड में शब्द शामिल होगा bash।
एक अलग शेल के साथ डायरेक्ट लॉन्चिंग ( sh)
$ sh foo.sh
The number of shells opened by terdon is 1
यह अलग है क्योंकि आप स्क्रिप्ट को चला रहे हैं shऔर नहीं bash। इसलिए, एकमात्र bashउदाहरण पैरेंट शेल है जहां आपने अपनी स्क्रिप्ट लॉन्च की है। उपर्युक्त सभी अन्य गोले shइसके बजाय चलाए जा रहे हैं ।
सोर्सिंग (या तो द्वारा .या source, एक ही बात)
$ . ./foo.sh
The number of shells opened by terdon is 2
जैसा कि मैंने ऊपर बताया, एक स्क्रिप्ट को सोर्स करने से यह मूल प्रक्रिया के समान शेल में चलने का कारण बनता है। हालाँकि, psकमांड को लॉन्च करने के लिए एक अलग उपखंड शुरू किया जाता है और जो कुल दो को लाता है।
अंतिम नोट के रूप में, चल रही प्रक्रियाओं को गिनने का सही तरीका पार्स करना नहीं है, psबल्कि उपयोग करना है pgrep। इन सभी समस्याओं से बचा जा सकता था आप बस चला रहे थे
pgrep -cu terdon bash
इसलिए, आपकी स्क्रिप्ट का एक कार्यशील संस्करण जो हमेशा सही संख्या प्रिंट करता है (नोट कमांड प्रतिस्थापन की अनुपस्थिति पर ध्यान दें):
#!/usr/bin/env bash
user="terdon"
printf "Open shells:"
pgrep -cu "$user" bash
जब लौटा और 2 (क्योंकि स्क्रिप्ट को चलाने के लिए एक नया बैश लॉन्च किया जाएगा) 1 लौटाएगा। shचाइल्ड प्रोसेस नहीं होने के बाद भी लॉन्च होने पर यह 1 हो जाएगा bash।