बैश शेल स्क्रिप्ट में चलने और खट्टे होने के बीच अंतर करना?


22

या तो मैं यहां जो पूछ रहा हूं वह बेहद अपरंपरागत / अपरंपरागत / जोखिम भरा है, या मेरे Google-फू कौशल केवल सूंघने तक नहीं हैं ...

एक bashशेल स्क्रिप्ट में, क्या यह बताने का कोई आसान तरीका है कि क्या यह किसी अन्य शेल स्क्रिप्ट से सॉर्ट हो रहा है, या क्या यह स्वयं द्वारा चलाया जा रहा है? दूसरे शब्दों में, क्या निम्नलिखित दो व्यवहारों के बीच अंतर करना संभव है?

# from another shell script
source myScript.sh

# from command prompt, or another shell script
./myScript.sh

मैं जो करने की सोच रहा हूं वह उपयोगिताओं जैसे शेल स्क्रिप्ट बनाने के लिए है जिसमें bashफ़ंक्शन शामिल हैं जो कि खट्टा होने पर उपलब्ध कराए जा सकते हैं। जब यह स्क्रिप्ट स्वयं द्वारा चलाई जा रही है, तो मैं इसे कुछ कार्यों को करना चाहूंगा, जो परिभाषित कार्यों के आधार पर भी होंगे। वहाँ पर्यावरण चर के कुछ प्रकार है कि इस खोल स्क्रिप्ट पर ले जा सकता है, जैसे

some_function() {
    # ...
}
if [ -z "$IS_SOURCED" ]; then
    some_function;
fi

अधिमानतः, मैं एक ऐसे समाधान की तलाश कर रहा हूं जिसमें किसी भी ध्वज चर को सेट करने के लिए कॉलर स्क्रिप्ट की आवश्यकता न हो।

संपादित करें : मुझे स्क्रिप्ट के सोर्सिंग और चलाने के बीच का अंतर पता है, मैं यहां यह पता लगाने की कोशिश कर रहा हूं कि क्या उस स्क्रिप्ट का अंतर बताना संभव है जिसका उपयोग किया जा रहा है (दोनों तरीकों से)।



@cuonglm ने मेरे प्रश्न को संपादित किया, मैं दोनों के बीच के अंतरों को जानता हूं, लेकिन मैं सोच रहा हूं कि क्या मैं प्रोग्राम स्क्रिप्ट को अंतर के रूप में अच्छी तरह बता सकता हूं।
hjk

4
@cuonglm: डुप्लिकेट नहीं। वह .कमांड के बारे में बिल्कुल नहीं पूछ रहा है , लेकिन यह पता लगाने के बारे में कि क्या स्क्रिप्ट में खराबी की गई है या सामान्य रूप से चलती है (यानी एक उपखंड में)।
जेंडर

स्टैक ओवरफ्लो में एक ही सवाल पर बहुत अच्छे जवाब: stackoverflow.com/a/28776166/96944
Jannie Theunissen

जवाबों:


19

हां - $ 0 चर स्क्रिप्ट का नाम देता है जैसा कि इसे चलाया गया था:

$ cat example.sh
#!/bin/bash
script_name=$( basename ${0#-} ) #- needed if sourced no path
this_script=$( basename ${BASH_SOURCE} )
if [[ ${script_name} = ${this_script} ]] ; then
    echo "running me directly"
else
    echo "sourced from ${script_name}"
fi 

$ cat example2.sh
#!/bin/bash
. ./example.sh

जो इस तरह चलता है:

$ ./example.sh
running me directly
$ ./example2.sh
example.sh sourced from example2.sh

यह एक इंटरैक्टिव शेल से स्रोत होने के लिए पूरा नहीं करता है, लेकिन आपको यह विचार मिलता है (मुझे आशा है)।

BASH_SOURCE शामिल करने के लिए अपडेट किया गया - धन्यवाद hjk


पर्याप्त नजदीक। :) छोटी बाधा जो मुझे स्क्रिप्ट के नाम को कम से कम निर्दिष्ट करने की आवश्यकता होगी, लेकिन अगर कोई अन्य व्यवहार्य समाधान नहीं है, तो मैं यह उत्तर
लूंगा

7

संयोजन @ Darkheart के वातावरण चर के साथ जवाब BASH_SOURCEचाल करने के लिए लगता है:

$ head example*.sh
==> example2.sh <==
#!/bin/bash
. ./example.sh

==> example.sh <==
#!/bin/bash
if [ "$(basename $0)" = "$(basename $BASH_SOURCE)" ]; then
    echo "running directly"
else
    echo "sourced from $0"
fi
$ ./example2.sh
sourced from ./example2.sh
$ ./example.sh
running directly

लगता है कि अभी भी एक सरल समाधान हो सकता है संपादित करें अगर मैं सिर्फ तत्वों की संख्या को गिनता हूं BASH_SOURCE:

if [ ${#BASH_SOURCE[@]} -eq 1 ]; then echo "running directly"; else echo "sourced from $0"; fi

1
लगता है कि हमें उसी समय 'bash_source' वैरिएबल मिला। :)
DarkHeart

@DarkHeart मैंने अपने उत्तर में सरणी आकार की गणना के उपयोग को भी जोड़ा है ... मुझे इस पथ पर इशारा करने के लिए धन्यवाद! : D
hjk

1

मैंने बस उसी तरह की लाइब्रेरी स्क्रिप्ट बनाई है जो बिजीबॉक्स की तरह काम करती है। इसमें, मैं परीक्षण करने के लिए निम्न फ़ंक्शन का उपयोग करता हूं अगर यह खट्टा हो रहा है ...

function isSourced () {
  [[ "${FUNCNAME[1]}" == "source" ]]  && return 0
  return 1
}

बाश-बनाए FUNCNAME सरणी अनिवार्य रूप से एक फ़ंक्शन कॉल स्टैक है। $FUNCNAME(या ${FUNCNAME[0]}) वर्तमान में निष्पादित कार्य का नाम है। ${FUNCNAME[1]}उस फ़ंक्शन का नाम है, जिसने इसे कहा है, और इसी तरह।

सबसे ऊपरी वस्तु स्क्रिप्ट के लिए एक विशेष मूल्य है। इसमें शामिल होगा ...

  • शब्द "स्रोत" यदि स्क्रिप्ट को सॉरी किया जा रहा है
  • शब्द "मुख्य" यदि स्क्रिप्ट निष्पादित हो रही है और परीक्षण एक फ़ंक्शन के भीतर से किया जा रहा है
  • "" (अशक्त) यदि स्क्रिप्ट निष्पादित हो रही है और परीक्षण किसी भी फ़ंक्शन के बाहर किया जा रहा है, अर्थात ... स्क्रिप्ट के स्तर पर ही।

ऊपर का कार्य वास्तव में केवल तभी काम करता है जब स्क्रिप्ट के स्तर पर बुलाया जाता है (जो मुझे आवश्यक है)। किसी अन्य फ़ंक्शन के अंदर से कॉल करने पर यह विफल हो जाएगा क्योंकि सरणी आइटम नंबर गलत होगा। इसे कहीं भी काम करने के लिए स्टैक के शीर्ष को खोजने और उस मूल्य का परीक्षण करने की आवश्यकता होती है, जो अधिक जटिल है।

यदि आपको इसकी आवश्यकता है, तो आप "स्टैक के शीर्ष" के साथ सरणी आइटम नंबर प्राप्त कर सकते हैं ...

  local _top_of_stack=$(( ${#FUNCNAME[@]} - 1 ))

${#FUNCNAME[@]}सरणी में आइटमों की संख्या है। शून्य-आधारित सरणी के रूप में, हम अंतिम # पाने के लिए 1 घटाते हैं।

इन तीन कार्यों को एक साथ पायथन के समान फ़ंक्शन स्टैक ट्रेस का उत्पादन करने के लिए उपयोग किया जाता है और वे आपको एक बेहतर विचार दे सकते हैं कि यह सब कैसे काम करता है ...

function inspFnStack () {
  local T+="  "
  local _at=
  local _text="\n"
  local _top=$(inspFnStackTop)
  local _fn=${FUNCNAME[1]}; [[ $_fn =~ source|main ]]  || _fn+="()"
  local i=_top; ((--i))
  #
  _text+="$i item function call stack for $_fn ...\n"
  _text+="| L   BASH_SOURCE{BASH_LINENO called from}.FUNCNAME  \n"
  _text+="| ---------------------------------------------------\n"
  while (( $i > 0 ))
  do
    _text+="| $i ${T}$(inspFnStackItem $i)\n"
    T+="  "
    ((--i))
  done
  #
  printf "$_text\n"
  #
  return 0
}

function inspFnStackItem ()  {
  local _i=$1
  local _fn=${FUNCNAME[$_i]}; [[ $_fn =~ source|main ]]  || _fn+="()"
  local _at="${BASH_LINENO[$_i-1]}"; [[ $_at == 1 ]]  && _at="trap"
  local _item="${BASH_SOURCE[$_i]}{${_at}}.$_fn"
  #
  printf "%s" "$_item"
  return 0
}

function inspFnStackTop () {
  # top stack item is 1 less than length of FUNCNAME array stack
  printf "%d\n" $(( ${#FUNCNAME[@]} - 1 ))
  #
  return 0
}

ध्यान दें कि FUNCNAME, BASH_SOURCE और BASH_LINENO बैश द्वारा बनाए गए 3 सरणियाँ हैं जैसे कि वे एक तीन आयामी सरणी थे।


0

बस यह जोड़ना चाहते हैं कि व्यूह को गिनना अविश्वसनीय प्रतीत होता है और किसी को sourceडॉट ( .) का उपयोग करने के बाद से शायद इसका उपयोग नहीं करना चाहिए (और sourceकीवर्ड को पूर्व निर्धारित करता है )।

उदाहरण के लिए, sourced.shकेवल लिपि युक्त echo $0:


$ . sourced.sh 
bash
$ source sourced.sh 
bash
$ chmod +x sourced.sh 
$ ./sourced.sh 
./sourced.sh
$ cat ./sourced.sh 
echo $0

तुलनात्मक समाधान ने बेहतर काम करने का सुझाव दिया।


0

एक तरीका है जो एक इंटरैक्टिव शेल से सोर्सिंग करते समय भी काम करता है :

if [ $BASH_LINENO -ne 0 ]; then
    some_function;
fi

BASH_LINENOचर भी सभी लाइनों बुला समारोह में मार डाला गया था के साथ एक सरणी है। यदि आप स्क्रिप्ट को सीधे कॉल करते हैं, या लाइन नंबर के अनुरूप पूर्णांक है तो यह शून्य होगा।

BASH_ * चर डॉक्स

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