ব্যাশ শেল স্ক্রিপ্টে চলমান এবং উত্সাহিত করার মধ্যে পার্থক্য?


22

হয় আমি এখানে যা জিজ্ঞাসা করছি তা অত্যন্ত রীতিহীন / অপ্রচলিত / ঝুঁকিপূর্ণ, বা আমার গুগল-ফু দক্ষতা স্নিগ্ধ করার মতো নয় ...

একটি bashশেল স্ক্রিপ্ট, সেখানে যদি এটা অন্য শেল স্ক্রিপ্ট দ্বারা sourced হচ্ছে বলার উপায় কোন সহজ, অথবা যখন এটি নিজে চালানো হচ্ছে? অন্য কথায়, নিম্নলিখিত দুটি আচরণের মধ্যে পার্থক্য করা কি সম্ভব?

# 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

অগ্রাধিকার হিসাবে, আমি এমন একটি সমাধান খুঁজছি যাতে কোনও ফ্ল্যাগ ভেরিয়েবল সেট করার জন্য কলার স্ক্রিপ্টের প্রয়োজন হয় না।

সম্পাদনা : আমি স্ক্রিপ্টটি সোর্সিং এবং চালনা করার মধ্যে পার্থক্য জানি, আমি যে স্ক্রিপ্টটি ব্যবহার হচ্ছে তা (উভয় উপায়ে) পার্থক্যটি জানা সম্ভব কিনা তবে আমি এখানে যা জানার চেষ্টা করছি ।



@ কুওগলম আমার প্রশ্নটি সম্পাদনা করেছেন, আমি উভয়ের মধ্যে পার্থক্য জানি কিন্তু আমি ভাবছি যে আমি যদি প্রোগ্রামটিগতভাবে শেল স্ক্রিপ্টকেও পার্থক্যটি বলতে পারি।
hjk

4
@ কুওগলম: নকল নয় Not তিনি .কমান্ডটি মোটেও জিজ্ঞাসা করছেন না , তবে কোনও স্ক্রিপ্ট উত্সাহিত হয়েছে বা সাধারণভাবে চালিত হয়েছে কিনা তা সনাক্ত করার জন্য (অর্থাত্ একটি সাবসিলে)।
জান্ডার

স্ট্যাক ওভারফ্লোতে একই প্রশ্নের খুব ভাল উত্তর: স্ট্যাকওভারফ্লো.
com

উত্তর:


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


খুব কাছাকাছি. :) ছোট বাধা যা আমাকে স্ক্রিপ্টের নামটি অন্তত নির্দিষ্ট করতে হবে, তবে অন্য কোনও কার্যকর সমাধান না হলে আমি এই উত্তরটি গ্রহণ করব ...
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
দেখে মনে হচ্ছে আমরা একই সাথে 'বাশ_সোর্স' পরিবর্তনশীলটি পেয়েছি। :)
ডার্কহার্ট

@ ডার্কহার্ট আমি আমার উত্তরটিতে অ্যারের আকার গণনা করার ব্যবহারটিও যুক্ত করেছি ... এই পথে আমাকে ইঙ্গিত করার জন্য ধন্যবাদ! : ডি
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_ * ভেরিয়েবল ডক্স

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.