"स्रोत file.sh", "./ile.sh", "sh file.sh", "का उपयोग करके शेल स्क्रिप्ट निष्पादित करने में क्या अंतर हैं।" ./file.sh "?


13

कोड पर एक नजर है:

#!/bin/bash
read -p "Eneter 1 for UID and 2 for LOGNAME" choice
if [ $choice -eq 1 ]
then
        read -p "Enter UID:  " uid
        logname=`cat /etc/passwd | grep $uid | cut -f1 -d:`
else
        read -p "Enter Logname:  " logname
fi
not=`ps -au$logname | grep -c bash`
echo  "The number of terminals opened by $logname are $not"

इस कोड का उपयोग उसी पीसी पर उपयोगकर्ता द्वारा खोले गए टर्मिनलों की संख्या का पता लगाने के लिए किया जाता है। अब दो उपयोगकर्ता लॉग ऑन हैं, x और y कहते हैं। मैं वर्तमान में y के रूप में लॉग इन हूं और उपयोगकर्ता x में 3 टर्मिनल खुले हैं। यदि मैं परिणाम के ऊपर बताए गए विभिन्न तरीकों का उपयोग करके y में इस कोड को निष्पादित करता हूं:

$ ./file.sh
The number of terminals opened by x are 3

$ bash file.sh
The number of terminals opened by x are 5

$ sh file.sh
The number of terminals opened by x are 3

$ source file.sh
The number of terminals opened by x are 4

$ . ./file.sh
The number of terminals opened by x are 4

नोट: मैंने इन सभी निष्पादनों के लिए १ और यूआईडी १००० पारित किया।

अब क्या आप कृपया इन सभी के बीच के अंतरों की व्याख्या कर सकते हैं?


अंतर वह है जिसे शेल निष्पादित किया जाता है। श

2
दो अंतिम निष्पादन भी भिन्न हैं क्योंकि आप एक ही संदर्भ में निष्पादित कर रहे हैं। यहां
जका इलाब

मैं दूसरे उपयोगकर्ता द्वारा खोले गए नंबर बैश इंस्टेंस (यहां यह टर्मिनलों की संख्या नहीं के बराबर है) को गिनने की कोशिश कर रहा हूं (वही उपयोगकर्ता जहां हमने लॉग इन किया था) और क्या आप बता सकते हैं कि प्रत्येक मामले में अलग-अलग नंबर क्यों आए हैं
रमाना रेड्डी

@RamanaReddy अन्य उपयोगकर्ता ने एक स्क्रिप्ट को चलाया हो या एक नया टैब शुरू किया हो। कौन जानता है?
मुरु

जवाबों:


21

एकमात्र मुख्य अंतर किसी स्क्रिप्ट के सोर्सिंग और निष्पादन के बीच है। source foo.shइसे स्रोत करेगा और आपके द्वारा दिखाए जाने वाले अन्य सभी उदाहरण निष्पादित कर रहे हैं। विस्तृत रूप में:

  1. ./file.sh

    यह file.shउस स्क्रिप्ट को निष्पादित करेगा जिसे वर्तमान निर्देशिका में है ( ./)। आम तौर पर, जब आप दौड़ते हैं command, तो शेल आपके $PATHद्वारा निष्पादन योग्य फ़ाइल नामक निर्देशिका के माध्यम से दिखेगा command। यदि आप पूर्ण पथ देते हैं, जैसे कि /usr/bin/commandया ./command, तो $PATHअनदेखा किया जाता है और उस विशिष्ट फ़ाइल को निष्पादित किया जाता है।

  2. ../file.sh

    यह मूल रूप से ./file.shसिवाय इसके कि वर्तमान निर्देशिका में देखने के बजाय file.sh, मूल निर्देशिका ( ../) में दिख रही है ।

  3. 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शेबंग लाइन (यदि मौजूद है) को ओवरराइड करेंगे और जो भी शेल आप इसे बताएंगे, उसके साथ स्क्रिप्ट को चलाएं।

  4. 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"

और इसे केवल एक ही टर्मिनल ओपन के साथ विभिन्न तरीकों से चलाएं:

  1. डायरेक्ट लॉन्चिंग ./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इसका उत्पादन किस तरह से दिखाया गया है ।

  2. स्पष्ट (बाश) खोल के साथ सीधा प्रक्षेपण

    $ bash foo.sh 
    The number of shells opened by terdon is 3

    यहाँ, क्योंकि आप के साथ चल रहे हैं bash foo.sh, का उत्पादन psदिखाएगा bash foo.shऔर गिना जाएगा। इसलिए, यहां हमारे पास मूल प्रक्रिया है, bashस्क्रिप्ट चलाने और क्लोन किए गए शेल (चल ​​रहे हैं ps) सभी को दिखाया गया है क्योंकि अब psउनमें से प्रत्येक दिखाएगा क्योंकि आपकी कमांड में शब्द शामिल होगा bash

  3. एक अलग शेल के साथ डायरेक्ट लॉन्चिंग ( sh)

    $ sh foo.sh
    The number of shells opened by terdon is 1

    यह अलग है क्योंकि आप स्क्रिप्ट को चला रहे हैं shऔर नहीं bash। इसलिए, एकमात्र bashउदाहरण पैरेंट शेल है जहां आपने अपनी स्क्रिप्ट लॉन्च की है। उपर्युक्त सभी अन्य गोले shइसके बजाय चलाए जा रहे हैं ।

  4. सोर्सिंग (या तो द्वारा .या 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


जब आप कहते हैं कि कमांड प्रतिस्थापन पैरेंट शेल की एक प्रति लॉन्च करता है, तो यह कॉपी सब-शेल से कैसे भिन्न होती है जैसे कि आप स्क्रिप्ट को .foo.sh के साथ चलाते हैं?
डिडिएर ए।

और जब आप कमांड प्रतिस्थापन के बिना pgrep चलाते हैं, तो मुझे लगता है कि यह उसी शेल के भीतर से चल रहा है जिसमें स्क्रिप्ट चलती है? तो सोर्सिंग के समान?
डिडिएर ए।

@didibus मुझे यकीन नहीं है कि आपका क्या मतलब है। कमांड सबस्टेशन एक उपधारा में चलता है; ./foo.shएक नए शेल में चलता है जो माता-पिता की नकल नहीं है। उदाहरण के लिए, यदि आप foo="bar"अपने टर्मिनल में सेट करते हैं और फिर एक स्क्रिप्ट चलाते हैं echo $foo, जो निष्पादित होती है , तो आपको एक खाली लाइन मिलेगी क्योंकि स्क्रिप्ट के शेल को वेरिएबल का मान विरासत में नहीं मिला होगा। pgrepएक अलग बाइनरी है, और हां यह आपके द्वारा चलाए जा रहे स्क्रिप्ट द्वारा चलाया जाता है।
टेराडॉन

मूल रूप से मुझे इस पर स्पष्टीकरण की आवश्यकता है: "कमांड प्रतिस्थापन की अनुपस्थिति पर ध्यान दें"। स्क्रिप्ट से pgrep बाइनरी को चलाना एक अतिरिक्त शेल क्यों नहीं जोड़ता है, लेकिन कमांड प्रतिस्थापन के साथ ps बाइनरी को रन करता है? दूसरे, मुझे "मूल शेल की प्रतिलिपि" पर स्पष्टीकरण की आवश्यकता है, क्या यह एक उप-शेल की तरह है जहां माता-पिता के शेल चर बच्चे की नकल करते हैं? कमांड प्रतिस्थापन क्यों करता है?
डिडिएर ए।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.