एकमात्र मुख्य अंतर किसी स्क्रिप्ट के सोर्सिंग और निष्पादन के बीच है। 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
।