কোনও স্ক্রিপ্ট উত্সাহিত হচ্ছে কিনা তা কীভাবে সনাক্ত করবেন


217

আমার একটি স্ক্রিপ্ট আছে যেখানে আমি এটি চাই না যে এটি exitউত্সাহিত হয়ে থাকলে এটি কল করতে পারে ।

আমি যাচাই করার কথা ভেবেছিলাম $0 == bashতবে স্ক্রিপ্টটি অন্য স্ক্রিপ্ট থেকে উত্সাহিত করা থাকলে, বা যদি ব্যবহারকারী এটির মতো আলাদা শেল থেকে উত্স করে তবে এটিতে সমস্যা রয়েছে ksh

কোনও স্ক্রিপ্ট উত্সাহিত হচ্ছে কিনা তা সনাক্ত করার কোনও নির্ভরযোগ্য উপায় আছে কি?


2
আমি কিছুক্ষণ আগে একই রকম সমস্যা পেয়েছি এবং সব ক্ষেত্রে 'প্রস্থান' এড়িয়ে সমাধান করেছি; "কিল-আইএনটি $$" উভয় ক্ষেত্রেই স্ক্রিপ্টটি নিরাপদে শেষ করে।
JESii

1
আপনি কি এই উত্তর লক্ষ্য করেছেন ? এটি 5 বছর পরে গৃহীত থেকে দেওয়া হয়, তবে এটিতে "ব্যাটারি অন্তর্ভুক্ত" রয়েছে।
রারাটিরু

উত্তর:


73

এটি ব্যাশ এবং কর্নের মধ্যে বহনযোগ্য বলে মনে হচ্ছে:

[[ $_ != $0 ]] && echo "Script is being sourced" || echo "Script is a subshell"

এটির অনুরূপ একটি লাইন বা একটি কার্য সম্পাদনের মতো pathname="$_"(পরে পরীক্ষা এবং ক্রিয়া সহ) স্ক্রিপ্টের প্রথম লাইনে বা শেবাংয়ের পরে লাইনটিতে (যা ব্যবহৃত হলে, কেএসএল হতে হবে এটির কাজ করার জন্য) সর্বাধিক পরিস্থিতি)।


10
দুর্ভাগ্যক্রমে এটি কাজ করার গ্যারান্টিযুক্ত নয়। ব্যবহারকারী সেট করে থাকে তাহলে BASH_ENV, $_স্ক্রিপ্ট উপরের থেকে শেষ কমান্ড চলবে BASH_ENV
মিকেল

30
আপনি যদি স্ক্রিপ্টটি কার্যকর করতে ব্যাশ ব্যবহার করেন তবে এটি কাজ করবে না, যেমন $ ব্যাশ স্ক্রিপ্ট.শ, তাহলে / _ /script.sh এর পরিবর্তে bin _ হবে / বিন / বাশ, যা আপনি প্রত্যাশা করেন, যখন স্ক্রিপ্টটি চালিত হয় when এইভাবে: / ./script.sh যে কোনও ক্ষেত্রে সনাক্তকরণ $_একটি সমস্যা।
বীরাওয়ান পূর্বন্তো

2
এই অনুরোধ পদ্ধতিগুলি পরীক্ষা করার জন্য অতিরিক্ত পরীক্ষাগুলি অন্তর্ভুক্ত করা যেতে পারে।
পরবর্তী বিজ্ঞপ্তি না হওয়া পর্যন্ত বিরতি দেওয়া হয়েছে।

8
দুর্ভাগ্যক্রমে, এটা ভুল! দেখতে আমার উত্তর
এফ Hauri

8
সংক্ষিপ্তসার হিসাবে: যদিও এই পদ্ধতিটি সাধারণত কার্যকর হয় তবে এটি দৃ rob় নয় ; এটি নিম্নলিখিত 2 টি পরিস্থিতিতে ব্যর্থ হয়েছে: (ক) bash script(শেল এক্সিকিউটেবলের মাধ্যমে প্রার্থনা, যা এই সমাধানটি সোর্স হিসাবে দুর্ব্যবহার করে ), এবং (খ) (খুব কম সম্ভাব্য) echo bash; . script(যদি $_স্ক্রিপ্টটি স্রোসিংয়ের শেলের সাথে মেলে তবে এই সমাধানটি এটিকে ভুল হিসাবে দেখায়) একটি সাবসেল )। কেবল শেল-নির্দিষ্ট বিশেষ ভেরিয়েবলগুলি (উদাহরণস্বরূপ $BASH_SOURCE) দৃust় সমাধানগুলির মঞ্জুরি দেয় (এটি অনুসরণ করে যে কোনও শক্তিশালী পসিক্স-সম্মতিযুক্ত সমাধান নেই)। এটা তোলে হয় একটি শক্তসমর্থ ক্রস শেল পরীক্ষা নৈপুণ্য করা সম্ভব, কষ্টকর যদিও।
mklement0

170

যদি আপনার বাশ সংস্করণ BASH_SOURCE অ্যারে ভেরিয়েবল সম্পর্কে জানে, তবে এর মতো কিছু চেষ্টা করুন:

# man bash | less -p BASH_SOURCE
#[[ ${BASH_VERSINFO[0]} -le 2 ]] && echo 'No BASH_SOURCE array variable' && exit 1

[[ "${BASH_SOURCE[0]}" != "${0}" ]] && echo "script ${BASH_SOURCE[0]} is being sourced ..."

11
সম্ভবত এটিই সবচেয়ে পরিষ্কার উপায় $ BASH_SOURCE ঠিক সেই উদ্দেশ্যে উদ্দেশ্যে করা হয়েছে।
কন-এফ-ব্যবহার করুন

4
দ্রষ্টব্য যে এটি ksh এর অধীনে কাজ করবে না যা ওপিতে নির্দিষ্ট করা শর্ত is
পরবর্তী বিজ্ঞপ্তি না হওয়া পর্যন্ত বিরতি দেওয়া হয়েছে।

2
ন্যায়বিচারের ${BASH_SOURCE[0]}পরিবর্তে ব্যবহার করার কোনও কারণ আছে কি $BASH_SOURCE? এবং ${0}বনাম $0?
হারাবান

4
BASH_SOURCEএকটি অ্যারে ভেরিয়েবল ( ম্যানুয়াল দেখুন ) যা সূত্রের স্ট্যাক ট্রেস ধারণ করে, যেখানে ${BASH_SOURCE[0]}সর্বশেষতম। চলক নামের অংশটি বাশ কী তা বলতে এখানে বন্ধনীগুলি ব্যবহার করা হয়। $0এই ক্ষেত্রে তারা প্রয়োজন হয় না , তবে তারা আঘাতও করে না। ;)
কনরাড

4
@Konrad, এবং যদি আপনি প্রসারিত $array, আপনি পেতে ${array[0]}ডিফল্টরূপে। তাহলে, আবারও কি কোনও কারণ আছে [...]?
চার্লস ডাফি

133

bashkshzshক্রস-শেল এক সহ , এর জন্য দৃ solutions় সমাধান , যুক্তিসঙ্গত দৃust়ভাবে শক্তিশালী পসিক্স-কমপ্লায়েন্ট সমাধান :

  • প্রদত্ত সংস্করণ নম্বরগুলি সেইগুলির উপর যার কার্যকারিতা যাচাই করা হয়েছিল - সম্ভবত, এই সমাধানগুলি অনেক পূর্ববর্তী সংস্করণগুলিতেও কাজ করে - প্রতিক্রিয়া স্বাগত

  • ব্যবহার POSIX শুধুমাত্র অতিরিক্ত বৈশিষ্ট্যগুলিও উপস্থিত রয়েছে (যেমন হিসাবে dash, যা হিসাবে কাজ করে /bin/shউবুন্টু দিকে), আছে কোন শক্তসমর্থ উপায় কিনা তা নির্ধারণ করতে একটি স্ক্রিপ্ট sourced হচ্ছে - শ্রেষ্ঠ জন্য নীচে দেখুন পড়তা

ওয়ান-লাইনারগুলি অনুসরণ করে - নীচে ব্যাখ্যা; ক্রস শেল সংস্করণ জটিল, তবে এটি দৃ rob়তার সাথে কাজ করা উচিত:

  • বাশ (3.57 এবং 4.4.19 এ যাচাই করা হয়েছে)

    (return 0 2>/dev/null) && sourced=1 || sourced=0
  • ksh (93u + তে যাচাই করা হয়েছে)

    [[ $(cd "$(dirname -- "$0")" && 
       printf '%s' "${PWD%/}/")$(basename -- "$0") != "${.sh.file}" ]] &&
         sourced=1 || sourced=0
  • zsh (5.0.5 এ যাচাই করা হয়েছে) - এটি কোনও ফাংশনের বাইরে কল করতে ভুলবেন না

    [[ $ZSH_EVAL_CONTEXT =~ :file$ ]] && sourced=1 || sourced=0
  • ক্রস শেল (ব্যাশ, কেএস, জেডএস)

    ([[ -n $ZSH_EVAL_CONTEXT && $ZSH_EVAL_CONTEXT =~ :file$ ]] || 
     [[ -n $KSH_VERSION && $(cd "$(dirname -- "$0")" &&
        printf '%s' "${PWD%/}/")$(basename -- "$0") != "${.sh.file}" ]] || 
     [[ -n $BASH_VERSION ]] && (return 0 2>/dev/null)) && sourced=1 || sourced=0
  • পসিক্স-কমপ্লায়েন্ট ; না এক-লাইনের (একক পাইপলাইন) প্রযুক্তিগত কারণের এবং জন্য না সম্পূর্ণরূপে শক্তসমর্থ (নিচে দেখুন):

    sourced=0
    if [ -n "$ZSH_EVAL_CONTEXT" ]; then 
      case $ZSH_EVAL_CONTEXT in *:file) sourced=1;; esac
    elif [ -n "$KSH_VERSION" ]; then
      [ "$(cd $(dirname -- $0) && pwd -P)/$(basename -- $0)" != "$(cd $(dirname -- ${.sh.file}) && pwd -P)/$(basename -- ${.sh.file})" ] && sourced=1
    elif [ -n "$BASH_VERSION" ]; then
      (return 0 2>/dev/null) && sourced=1 
    else # All other shells: examine $0 for known shell binary filenames
      # Detects `sh` and `dash`; add additional shell filenames as needed.
      case ${0##*/} in sh|dash) sourced=1;; esac
    fi

ব্যাখ্যা:


সজোরে আঘাত

(return 0 2>/dev/null) && sourced=1 || sourced=0

দ্রষ্টব্য: প্রযুক্তিটি ব্যবহারকারীর 7554163 এর উত্তর থেকে অভিযোজিত হয়েছিল , কারণ এটি আসল সমাধানের চেয়ে আরও শক্তিশালী বলে প্রমাণিত হয়েছে, [[ $0 != "$BASH_SOURCE" ]] && sourced=1 || sourced=0[1]

  • বাশ returnকেবলমাত্র ফাংশন থেকে এবং কোনও স্ক্রিপ্টের শীর্ষ-স্তরের স্কোপগুলিতে বিবৃতি দেয় , কেবলমাত্র স্ক্রিপ্টটি উত্সাহিত হলে

    • যদি অ-উত্সাহিত স্ক্রিপ্টের returnশীর্ষ-স্তরের স্কোপ ব্যবহার করা হয় তবে একটি ত্রুটি বার্তা প্রেরণ করা হয় এবং প্রস্থান কোডটি সেট করা থাকে ।1
  • (return 0 2>/dev/null), executes returnএকটি subshell এবং শুষে ত্রুটি বার্তা; পরে প্রস্থান কোডটি ইঙ্গিত দেয় কিনা স্ক্রিপ্ট sourced হয়েছিল ( 0) অথবা না ( 1), যা দিয়ে ব্যবহার করা হয় &&এবং ||সেট করার অপারেটার sourcedতদনুসারে পরিবর্তনশীল।

    • একটি সাব-শেল ব্যবহার করা প্রয়োজনীয়, কারণ returnকোনও উত্সযুক্ত স্ক্রিপ্টের শীর্ষ-স্তরের স্কোপকে কার্যকর করা স্ক্রিপ্ট থেকে প্রস্থান করবে।
    • @ হাওজুনের কাছে টুপিটির টিপ , যিনি স্পষ্টভাবে অপারেন্ড 0হিসাবে ব্যবহার করে কমান্ডটিকে আরও শক্তিশালী করেছিলেন return; তিনি নোট করেছেন: প্রতি বাশ সহায়তা return [N]: "এন বাদ দিলে, ফেরতের স্থিতি সর্বশেষ আদেশের command" ফলস্বরূপ, returnব্যবহারকারীর শেলের সর্বশেষ কমান্ডটিতে শূন্য -হীন রিটার্ন মান থাকলে পূর্ববর্তী সংস্করণ [যা অপপ্রচার ছাড়াই কেবলমাত্র ব্যবহৃত হয়েছিল ] ভুল ফলাফল দেয়।

ksh

[[ \
   $(cd "$(dirname -- "$0")" && printf '%s' "${PWD%/}/")$(basename -- "$0") != \
   "${.sh.file}" \
]] && 
sourced=1 || sourced=0

বিশেষ পরিবর্তনশীল ${.sh.file}কিছুটা অনুরূপ $BASH_SOURCE; নোট যে বাশ, zsh, এবং ড্যাশ মধ্যে ${.sh.file}একটি সিনট্যাক্স ত্রুটি ঘটায় , তাই একাধিক শেল স্ক্রিপ্টে শর্তসাপেক্ষে এটি সম্পাদন করতে ভুলবেন না ।

বাশের মতো নয় , $0এবং নন-সোর্স ক্ষেত্রে একেবারে অভিন্ন ${.sh.file}হওয়ার গ্যারান্টি দেওয়া হয় না , যেমন একটি আপেক্ষিক পথ হতে পারে , যদিও সর্বদা একটি পুরো পথ হয়, তাই তুলনার আগে অবশ্যই একটি সম্পূর্ণ পথে সমাধান করা উচিত।$0${.sh.file}$0


zsh

[[ $ZSH_EVAL_CONTEXT =~ :file$ ]] && sourced=1 || sourced=0

$ZSH_EVAL_CONTEXTমূল্যায়নের প্রসঙ্গে তথ্য রয়েছে - এটি কোনও ফাংশনের বাইরে কল করুন। একটি উত্সাহিত স্ক্রিপ্টের ভিতরে [এর শীর্ষ-স্তরের স্কোপ] $ZSH_EVAL_CONTEXT শেষ হয় :file

সতর্কীকরণ: ইনসাইড কমান্ড প্রতিকল্পন, zsh আপনার স্বাক্ষরে :cmdsubst, পরীক্ষা, যাতে $ZSH_EVAL_CONTEXTজন্য :file:cmdsubst$আছে।


শুধুমাত্র পসিক্স বৈশিষ্ট্য ব্যবহার করা

আপনি যদি কিছু ধারনা করতে ইচ্ছুক হন তবে আপনি আপনার স্ক্রিপ্টটি কার্যকর করতে পারে এমন শেলগুলির বাইনারি ফাইলের নামগুলি জানতে পেরে আপনার স্ক্রিপ্টটি সস করা হচ্ছে কিনা সে সম্পর্কে আপনি একটি যুক্তিসঙ্গত, তবে বোকা-প্রমাণ অনুমান করতে পারবেন না । উল্লেখযোগ্যভাবে, এর অর্থ হ'ল যদি আপনার স্ক্রিপ্টটি অন্য স্ক্রিপ্টের দ্বারা উত্সাহিত করা হয় তবে এই পদ্ধতির ব্যর্থতা ।

খনিটির এই উত্তরে "কীভাবে উত্সাহিত প্রার্থনাগুলি পরিচালনা করবেন" বিভাগটি এমন প্রান্তের বিষয়গুলি নিয়ে আলোচনা করে যা কেবলমাত্র পসিক্স বৈশিষ্ট্যগুলি দিয়ে বিশদভাবে পরিচালনা করা যায় না

এটি স্ট্যান্ডার্ড আচরণের উপর নির্ভর করে $0, যা zshউদাহরণস্বরূপ প্রদর্শিত হয় না

সুতরাং, নিরাপদ পদ্ধতির উপরের সমস্ত শক্তিশালী শেলগুলির ফলব্যাক সমাধানের সাথে উপরের দৃ the়, শেল-নির্দিষ্ট পদ্ধতিগুলিকে একত্রিত করা

স্টাফেন দেসনাক্সের টুপি এবং অনুপ্রেরণার জন্য তার জবাব (আমার ক্রস শেল স্টেটমেন্ট এক্সপ্রেশনটিকে একটি shসামঞ্জস্যপূর্ণ ifবিবৃতিতে রূপান্তর করা এবং অন্যান্য শেলগুলির জন্য একটি হ্যান্ডলার যুক্ত করা)।

sourced=0
if [ -n "$ZSH_EVAL_CONTEXT" ]; then 
  case $ZSH_EVAL_CONTEXT in *:file) sourced=1;; esac
elif [ -n "$KSH_VERSION" ]; then
  [ "$(cd $(dirname -- $0) && pwd -P)/$(basename -- $0)" != "$(cd $(dirname -- ${.sh.file}) && pwd -P)/$(basename -- ${.sh.file})" ] && sourced=1
elif [ -n "$BASH_VERSION" ]; then
  (return 0 2>/dev/null) && sourced=1 
else # All other shells: examine $0 for known shell binary filenames
  # Detects `sh` and `dash`; add additional shell filenames as needed.
  case ${0##*/} in sh|dash) sourced=1;; esac
fi

[1] user1902689 যে আবিষ্কৃত [[ $0 != "$BASH_SOURCE" ]]উৎপাদনের একটি মিথ্যা ইতিবাচক যখন আপনি একটি স্ক্রিপ্ট চালানো অবস্থিত$PATH তার পাশ দিয়ে নিছক ফাইলের নাম থেকে bashবাইনারি; উদাহরণস্বরূপ, bash my-scriptকারণ $0তখন ঠিক my-script, যেখানে $BASH_SOURCEরয়েছে পুরো পথ । আপনি সাধারণত স্ক্রিপ্ট ডাকা এই প্রযুক্তিটি ব্যবহার না করেন $PATH- আপনি শুধু তাদের ডাকা চাই সরাসরি ( my-script) - এটা হল যখন সঙ্গে মিলিত সহায়ক -xজন্য ডিবাগ


1
এমন একটি বিস্তৃত উত্তরের জন্য কুডোস।
DrUseful

75

@ ডেনিস উইলিয়ামসনের উত্তরটি পড়ার পরে কিছু সমস্যা রয়েছে, নীচে দেখুন:

এই প্রশ্ন হিসাবে দাঁড়ানো এবং , এই উত্তর সম্পর্কে আরও একটি অংশ আছে ... নিচে দেখ.

সহজ পথ

[ "$0" = "$BASH_SOURCE" ]

আসুন চেষ্টা করুন (উড়ে যাওয়ার কারণে যে বাশ পারে ;-):

source <(echo $'#!/bin/bash
           [ "$0" = "$BASH_SOURCE" ] && v=own || v=sourced;
           echo "process $$ is $v ($0, $BASH_SOURCE)" ')
process 29301 is sourced (bash, /dev/fd/63)

bash <(echo $'#!/bin/bash
           [ "$0" = "$BASH_SOURCE" ] && v=own || v=sourced;
           echo "process $$ is $v ($0, $BASH_SOURCE)" ')
process 16229 is own (/dev/fd/63, /dev/fd/63)

আমি sourceপরিবর্তে .পঠনযোগ্যতার জন্য ব্যবহার করি (যেমন .একটি উপাধি হিসাবে source):

. <(echo $'#!/bin/bash
           [ "$0" = "$BASH_SOURCE" ] && v=own || v=sourced;
           echo "process $$ is $v ($0, $BASH_SOURCE)" ')
process 29301 is sourced (bash, /dev/fd/63)

নোট করুন যে প্রক্রিয়া উত্সাহিত অবস্থায় প্রক্রিয়া নম্বর পরিবর্তন হয় না :

echo $$
29301

$_ == $0তুলনা কেন ব্যবহার করবেন না

অনেকগুলি ক্ষেত্রে নিশ্চিত হওয়ার জন্য, আমি একটি সত্য স্ক্রিপ্ট লিখতে শুরু করি :

#!/bin/bash

# As $_ could be used only once, uncomment one of two following lines

#printf '_="%s", 0="%s" and BASH_SOURCE="%s"\n' "$_" "$0" "$BASH_SOURCE"
[[ "$_" != "$0" ]] && DW_PURPOSE=sourced || DW_PURPOSE=subshell

[ "$0" = "$BASH_SOURCE" ] && BASH_KIND_ENV=own || BASH_KIND_ENV=sourced;
echo "proc: $$[ppid:$PPID] is $BASH_KIND_ENV (DW purpose: $DW_PURPOSE)"

এটিকে একটি ফাইলটিতে অনুলিপি করুন testscript:

cat >testscript   
chmod +x testscript

এখন আমরা পরীক্ষা করতে পারি:

./testscript 
proc: 25758[ppid:24890] is own (DW purpose: subshell)

ঠিক আছে.

. ./testscript 
proc: 24890[ppid:24885] is sourced (DW purpose: sourced)

source ./testscript 
proc: 24890[ppid:24885] is sourced (DW purpose: sourced)

ঠিক আছে.

তবে -xপতাকা যুক্ত করার আগে স্ক্রিপ্ট পরীক্ষা করার জন্য :

bash ./testscript 
proc: 25776[ppid:24890] is own (DW purpose: sourced)

বা প্রাক-সংজ্ঞায়িত ভেরিয়েবলগুলি ব্যবহার করতে:

env PATH=/tmp/bintemp:$PATH ./testscript 
proc: 25948[ppid:24890] is own (DW purpose: sourced)

env SOMETHING=PREDEFINED ./testscript 
proc: 25972[ppid:24890] is own (DW purpose: sourced)

এটি আর কাজ করবে না।

5 তম লাইন থেকে 6 তম লাইনে মন্তব্য সরানো আরও পঠনযোগ্য উত্তর দেবে:

./testscript 
_="./testscript", 0="./testscript" and BASH_SOURCE="./testscript"
proc: 26256[ppid:24890] is own

. testscript 
_="_filedir", 0="bash" and BASH_SOURCE="testscript"
proc: 24890[ppid:24885] is sourced

source testscript 
_="_filedir", 0="bash" and BASH_SOURCE="testscript"
proc: 24890[ppid:24885] is sourced

bash testscript 
_="/bin/bash", 0="testscript" and BASH_SOURCE="testscript"
proc: 26317[ppid:24890] is own

env FILE=/dev/null ./testscript 
_="/usr/bin/env", 0="./testscript" and BASH_SOURCE="./testscript"
proc: 26336[ppid:24890] is own

কঠিনতর: এখন ...

যেমন আমি ব্যবহার করি না অনেকগুলি, ম্যান পৃষ্ঠায় কিছু পড়ার পরে, আমার চেষ্টা রয়েছে:

#!/bin/ksh

set >/tmp/ksh-$$.log

এটিকে অনুলিপি করুন testfile.ksh:

cat >testfile.ksh
chmod +x testfile.ksh

দুইবার চালানোর চেয়ে:

./testfile.ksh
. ./testfile.ksh

ls -l /tmp/ksh-*.log
-rw-r--r-- 1 user user   2183 avr 11 13:48 /tmp/ksh-9725.log
-rw-r--r-- 1 user user   2140 avr 11 13:48 /tmp/ksh-9781.log

echo $$
9725

এবং দেখো:

diff /tmp/ksh-{9725,9781}.log | grep ^\> # OWN SUBSHELL:
> HISTCMD=0
> PPID=9725
> RANDOM=1626
> SECONDS=0.001
>   lineno=0
> SHLVL=3

diff /tmp/ksh-{9725,9781}.log | grep ^\< # SOURCED:
< COLUMNS=152
< HISTCMD=117
< LINES=47
< PPID=9163
< PS1='$ '
< RANDOM=29667
< SECONDS=23.652
<   level=1
<   lineno=1
< SHLVL=2

একটি উত্সাহিত রান মধ্যে কিছু পরিবর্তনশীল উত্তরাধিকারী আছে , কিন্তু সত্যিই সম্পর্কিত কিছুই ...

এমনকি আপনি এটি পরীক্ষা করে দেখতে পারেন যে এটি $SECONDSখুব কাছাকাছি রয়েছে 0.000তবে এটি কেবল ম্যানুয়ালি সোর্স কেসগুলি নিশ্চিত করে ...

এমনকি আপনি পিতামাতা কি তা যাচাই করার চেষ্টা করতে পারেন :

এটি আপনার মধ্যে রাখুন testfile.ksh:

ps $PPID

চেয়ে:

./testfile.ksh
  PID TTY      STAT   TIME COMMAND
32320 pts/4    Ss     0:00 -ksh

. ./testfile.ksh
  PID TTY      STAT   TIME COMMAND
32319 ?        S      0:00 sshd: user@pts/4

বা ps ho cmd $PPID, কিন্তু এই কাজটি কেবলমাত্র এক স্তরের অধীনতার জন্য ...

দুঃখিত, আমি এটির আধ্যাত্মিক উপায় খুঁজে পাইনি


[ "$0" = "$BASH_SOURCE" ] || [ -z "$BASH_SOURCE" ]পাইপের মাধ্যমে পড়া স্ক্রিপ্টগুলির জন্য ( cat script | bash)।
হ্যাক্রে

2
নোট করুন যে এটির .জন্য কোনও উপ নাম নয় source, এটি আসলে অন্যভাবে। source somescript.shবাশ-ইসম এবং পোর্টেবল নয়, . somescript.shএটি পসিক্স এবং বহনযোগ্য আইআইআরসি।
ড্রাগন 788

32

BASH_SOURCE[]উত্তর (ব্যাশ-3.0 এবং পরবর্তী) সবচেয়ে সহজ বলে মনে হয়, যদিও BASH_SOURCE[]হয় একটি ফাংশন শরীরের বাইরে কাজ নথিভুক্ত না (এটা বর্তমানে মানুষ পৃষ্ঠার সাথে মতানৈক্য, কর্মক্ষেত্রে ঘটবে)।

সবচেয়ে শক্তিশালী উপায়, যেমন বীরাওয়ান পূর্বওয়ান্টোর পরামর্শ অনুসারে FUNCNAME[1] একটি ফাংশনটির মধ্যে যাচাই করা :

function mycheck() { declare -p FUNCNAME; }
mycheck

তারপর:

$ bash sourcetest.sh
declare -a FUNCNAME='([0]="mycheck" [1]="main")'
$ . sourcetest.sh
declare -a FUNCNAME='([0]="mycheck" [1]="source")'

এটি হ'ল আউটপুট caller, মানগুলি পরীক্ষা করে mainএবং sourceকলারের প্রসঙ্গটি পৃথক করে। ব্যবহার FUNCNAME[]করে আপনি callerআউটপুট ক্যাপচারিং এবং পার্সিং সাশ্রয় করেন । সঠিক হওয়ার জন্য আপনার স্থানীয় কলের গভীরতা জানতে বা গণনা করা দরকার। অন্য কোনও ফাংশন বা স্ক্রিপ্টের মধ্যে থেকে কোনও স্ক্রিপ্টের মতো উত্সগুলি সন্ধানের ফলে অ্যারে (স্ট্যাক) আরও গভীর হয়। ( FUNCNAMEএকটি বিশেষ বাশ অ্যারের ভেরিয়েবল, এটি কল স্ট্যাকের সাথে সঙ্গতিপূর্ণ সূচকগুলি হওয়া উচিত, যতক্ষণ না এটি কখনও না unset))

function issourced() {
    [[ ${FUNCNAME[@]: -1} == "source" ]]
}

(বাশ -২.২ এবং পরে আপনি ${FUNCNAME[-1]}অ্যারেতে শেষ আইটেমটির পরিবর্তে সহজ ফর্মটি ব্যবহার করতে পারেন Den নীচে ডেনিস উইলিয়ামসনের মন্তব্যে উন্নত ও সরলীকৃত ধন্যবাদ))

তবে আপনার সমস্যা হিসাবে বলা হয়েছে " আমার কাছে একটি স্ক্রিপ্ট রয়েছে যেখানে এটি উত্সাহিত হলে এটি 'প্রস্থান' কল করতে চাই না " " bashএই পরিস্থিতির জন্য সাধারণ প্রতিমাটি হ'ল:

return 2>/dev/null || exit

যদি স্ক্রিপ্টটি উত্সাহিত হয়ে থাকে তবে returnতা উত্সাহিত স্ক্রিপ্টটি শেষ করে কলারে ফিরে আসবে।

যদি স্ক্রিপ্টটি কার্যকর করা হচ্ছে, তবে returnএকটি ত্রুটি (পুনর্নির্দেশ) ফিরিয়ে দেবে, এবং exitস্ক্রিপ্টটিকে স্বাভাবিক হিসাবে শেষ করে দেবে। উভয় returnএবং exitপ্রয়োজন হলে একটি প্রস্থান কোড নিতে পারে।

দুঃখের বিষয়, এটি কাজ করে না ksh(কমপক্ষে এটি এখানে থাকা টি এন্ড টি উদ্ভূত সংস্করণে নয়), এটি কোনও ফাংশন বা ডট-সোর্স স্ক্রিপ্টের বাইরে আহ্বান returnকরা সমতুল্য হিসাবে বিবেচনা করে exit

আপডেট করা : আপনি সমসাময়িক সংস্করণগুলিতে যা করতে পারেন তা kshহ'ল বিশেষ ভেরিয়েবল .sh.levelযা ফাংশন কল গভীরতায় সেট করা আছে তা পরীক্ষা করা । একটি চালিত স্ক্রিপ্টের জন্য এটি প্রথমে আনসেট করা হবে, একটি বিন্দু-উত্সযুক্ত স্ক্রিপ্টের জন্য এটি সেট করা হবে 1।

function issourced {
    [[ ${.sh.level} -eq 2 ]]
}

issourced && echo this script is sourced

এটি বাশ সংস্করণের মতো ততটা শক্তিশালী নয়, আপনি issourced()উপরের স্তরের বা একটি পরিচিত ফাংশন গভীরতায় যে ফাইলটি পরীক্ষা করছেন তা আপনাকে অবশ্যই আবেদন করতে হবে ।

(আপনি আগ্রহী হতে পারেন এই কোড GitHub উপর একটি ব্যবহার করে যা kshশৃঙ্খলা ফাংশন এবং কিছু ডিবাগ ফাঁদ কপট ব্যাশ অনুকরণ FUNCNAMEঅ্যারে।)

ক্যানোনিকাল উত্তর এখানে: http://mywiki.wooledge.org/BashFAQ/109 এছাড়াও $-শেল রাষ্ট্রের অন্য সূচক (অপূর্ণ যদিও) হিসাবে প্রস্তাব দেয়।


মন্তব্য:

  • "মুখ্য" এবং "উত্স" ( বিল্টিনকে ওভাররাইড করা ) নামে ব্যাশ ফাংশন তৈরি করা সম্ভব , এই নামগুলি উপস্থিত হতে পারে FUNCNAME[]তবে যতক্ষণ না কেবল অ্যারেটিতে শেষ আইটেমটি পরীক্ষা করা হয় ততক্ষণ কোনও অস্পষ্টতা নেই।
  • আমার কাছে ভাল উত্তর নেই pdksh। আমি যে নিকটতম জিনিসটি পাই তা কেবলমাত্র pdkshসেখানেই প্রযোজ্য যেখানে স্ক্রিপ্টের প্রতিটি সোর্সিং একটি নতুন ফাইল বর্ণনাকারী খোলে (মূল স্ক্রিপ্টের জন্য 10 দিয়ে শুরু করে)। আপনি নির্ভর করতে চান এমন কিছু না সম্ভবত ...

${FUNCNAME[(( ${#FUNCNAME[@]} - 1 ))]}স্ট্যাকের সর্বশেষ (নীচে) আইটেমটি কীভাবে পাবেন? তারপরে "মেইন" (ওপিকে অবহেলা) এর বিরুদ্ধে পরীক্ষা করা আমার পক্ষে সবচেয়ে নির্ভরযোগ্য।
অ্যাড্রিয়ান গন্টার

আমার যদি একটি PROMPT_COMMANDসেট থাকে, যা FUNCNAMEআমি চালিত হলে অ্যারের শেষ সূচক হিসাবে দেখাবে source sourcetest.sh। চেক (খুঁজছেন ইনভার্টারিং mainগত সূচক হিসাবে) আরো জোরালো বলে মনে হয়: is_main() { [[ ${FUNCNAME[@]: -1} == "main" ]]; }
ডিমো 414

1
ম্যান-পৃষ্ঠায় বলা হয়েছে, এটি FUNCNAMEকেবল ফাংশনে উপলব্ধ। আমার পরীক্ষাগুলি অনুসারে declare -p FUNCNAME, bashআলাদা আচরণ করে। v4.3 বাইরে ফাংশন একটি ত্রুটি দেয়, যখন v4.4 দেয় declare -a FUNCNAME। উভয় (!) আগমন mainজন্য ${FUNCNAME[0]}প্রধান লিপিতে (যদি এটি মৃত্যুদন্ড কার্যকর করা হয়) যখন $FUNCNAMEকিছুই দেয়। এবং: $BASH_SOURCEবাইরের ফাংশনগুলি ব্যবহার করে "আব" সেখানে অনেকগুলি স্ক্রিপ্ট রয়েছে যা আমি সন্দেহ করি যে এটি এটিকে পরিবর্তন করতে পারে বা পরিবর্তন করতে পারে।
টিনো

24

সম্পাদকের দ্রষ্টব্য: এই উত্তরের সমাধানটি bashদৃust়তার সাথে কাজ করে তবে কেবলমাত্র । এটিকে প্রবাহিত করা যায়
(return 2>/dev/null)

টি এল; ডিআর

একটি returnবিবৃতি কার্যকর করার চেষ্টা করুন । যদি স্ক্রিপ্টটি উত্সাহিত না হয় তবে এটি ত্রুটি বাড়িয়ে তুলবে। আপনি সেই ত্রুটিটি ধরতে পারেন এবং আপনার প্রয়োজন অনুযায়ী এগিয়ে যেতে পারেন।

এটি একটি ফাইলে রাখুন এবং কল করুন, বলুন, পরীক্ষা করুন sh

#!/usr/bin/env sh

# Try to execute a `return` statement,
# but do it in a sub-shell and catch the results.
# If this script isn't sourced, that will raise an error.
$(return >/dev/null 2>&1)

# What exit code did that give?
if [ "$?" -eq "0" ]
then
    echo "This script is sourced."
else
    echo "This script is not sourced."
fi

সরাসরি এটি কার্যকর করুন:

shell-prompt> sh test.sh
output: This script is not sourced.

এটি উত্স:

shell-prompt> source test.sh
output: This script is sourced.

আমার জন্য, এটি zsh এবং ব্যাশে কাজ করে।

ব্যাখ্যা

returnযদি আপনি একটি ফাংশন বাইরে অথবা যদি স্ক্রিপ্ট sourced হয় না এটি চালানো চেষ্টা বিবৃতি একটি ত্রুটি তুলব। শেল প্রম্পট থেকে এটি চেষ্টা করুন:

shell-prompt> return
output: ...can only `return` from a function or sourced script

আপনাকে সেই ত্রুটি বার্তাটি দেখার দরকার নেই, সুতরাং আপনি আউটপুটটি ডিভ / নালটিতে পুনর্নির্দেশ করতে পারেন:

shell-prompt> return >/dev/null 2>&1

এবার প্রস্থান কোডটি পরীক্ষা করুন। 0 এর অর্থ ঠিক আছে (কোনও ত্রুটি ঘটেনি), 1 এর অর্থ একটি ত্রুটি ঘটেছে:

shell-prompt> echo $?
output: 1

আপনি returnসাব-শেলের অভ্যন্তরে বিবৃতিটি কার্যকর করতে চান । যখন returnবিবৃতি এটি চালায়। । । আমরা হব . । । আয়। আপনি যদি এটি একটি সাব-শেলতে চালিত করেন তবে এটি আপনার স্ক্রিপ্ট থেকে ফিরে আসার পরিবর্তে সেই সাব-শেল থেকে ফিরে আসবে। সাব-শেলটিতে সম্পাদন করতে, এটিকে মোড়ানো করুন $(...):

shell-prompt> $(return >/dev/null 2>$1)

এখন, আপনি সাব-শেলটির প্রস্থান কোড দেখতে পাবেন, যা 1 হওয়া উচিত, কারণ সাব-শেলের ভিতরে একটি ত্রুটি উত্থাপিত হয়েছিল:

shell-prompt> echo $?
output: 1

এটি আমার জন্য 0.5.8-2.1ubuntu2 এ ব্যর্থ হয় $ readlink $(which sh) dash $ . test.sh This script is sourced. $ ./test.sh This script is sourced.
ফিল রুশম্যান

3
পসিক্সreturn শীর্ষ স্তরে কী করা উচিত তা নির্দিষ্ট করে না ( pubs.opengroup.org/onlinepubs/9699919799/utilities/… )। dashশেল একইরূপে একটি returnহিসাবে শীর্ষ স্তরে exit। অন্যান্য শেল শীর্ষ স্তরে পছন্দ করে bashবা zshঅনুমতি দেয় না return, যা বৈশিষ্ট্য হ'ল এই কৌশলগুলি যেমন শোষণ করে।
user5754163

এটি sh এ কাজ করে যদি আপনি $সাবশেলের আগে মুছে ফেলেন । এটির (return >/dev/null 2>&1)পরিবর্তে ব্যবহার করুন $(return >/dev/null 2>&1)- তবে এটি ব্যাশে কাজ করা বন্ধ করে দেয়।
এপিমনাম

@Eponymous: যেহেতু dash, যেখানে এই সমাধান কাজ না করে, হিসাবে কাজ করে shউবুন্টু উপর, উদাহরণস্বরূপ, এই সমাধান না সাধারণত সঙ্গে কাজ sh। সমাধানটি আমার সাথে বাশ ৩.২.৫7 এবং ৪.৪.৫-এ কাজ করে - $আগে বা ছাড়া (...)(যদিও এর আগে কখনও ভাল কারণ নেই $)।
mklement0

2
returnsourceএকটি খারাপ-প্রস্থান কমান্ডের ঠিক পরে স্ক্রিপ্টগুলিতে আইএনএন করার সময় একটি এক্সপ্লিট রিটার্ন মান ভেঙে যায় ing বর্ধন সম্পাদনা প্রস্তাবিত।
ডিমেজি

12

এফডাব্লুআইডাব্লু, অন্যান্য সমস্ত উত্তর পড়ার পরে, আমি আমার জন্য নিম্নলিখিত সমাধান নিয়ে এসেছি:

আপডেট: প্রকৃতপক্ষে, কেউ অন্য উত্তরে একটি সঠিক-ত্রুটিযুক্ত ত্রুটি দেখেছিল যা আমারও ক্ষতিগ্রস্থ হয়েছিল। আমি মনে করি এখানে আপডেটটিও একটি উন্নতি (আপনি কৌতূহলী হলে সম্পাদনাগুলি দেখুন)।

এটি সমস্ত স্ক্রিপ্টগুলির জন্য কাজ করে, যা শুরু হয়#!/bin/bash তবে বিভিন্ন শেল দ্বারা উত্সাহিত করা যেতে পারে পাশাপাশি mainফাংশনের বাইরে রাখা কিছু তথ্য (যেমন সেটিংস) শিখতে পারে।

নীচের মতামত অনুসারে, এই উত্তরটি এখানে দৃশ্যত সমস্ত bashরূপের জন্য কার্যকরভাবে কাজ করে না । এছাড়াও সিস্টেমগুলির জন্য নয়, যেখানে /bin/shভিত্তিক bash। IE এটি bashম্যাকওএসে v3.x এর জন্য ব্যর্থ । (বর্তমান আমি কীভাবে এটি সমাধান করব জানি না))

#!/bin/bash

# Function definitions (API) and shell variables (constants) go here
# (This is what might be interesting for other shells, too.)

# this main() function is only meant to be meaningful for bash
main()
{
# The script's execution part goes here
}

BASH_SOURCE=".$0" # cannot be changed in bash
test ".$0" != ".$BASH_SOURCE" || main "$@"

শেষ 2 টি লাইনের পরিবর্তে আপনি নিম্নলিখিত BASH_SOURCEশেলগুলিতে সেট না করার জন্য নিম্নলিখিত (আমার মতে কম পাঠযোগ্য) কোডটি ব্যবহার করতে পারেন এবং এতে set -eকাজ করার অনুমতি দিতে পারেন main:

if ( BASH_SOURCE=".$0" && exec test ".$0" != ".$BASH_SOURCE" ); then :; else main "$@"; fi

এই স্ক্রিপ্ট-রেসিপিতে নিম্নলিখিত বৈশিষ্ট্য রয়েছে:

  • যদি bashসাধারণ উপায়ে মৃত্যুদন্ড কার্যকর করা হয় তবে mainতাকে ডাকা হয়। দয়া করে নোট করুন যে এতে কোনও কল অন্তর্ভুক্ত নেই bash -x script(যেখানে scriptকোনও পাথ থাকে না) নীচে দেখুন।

  • যদি উত্সাহিত হয় bash, mainকেবলমাত্র কল হয়, যদি কলিং স্ক্রিপ্টের একই নামটি ঘটে থাকে। (উদাহরণস্বরূপ, যদি এটি নিজেই উত্স দেয় বা তার মাধ্যমে bash -c 'someotherscript "$@"' main-script args..কোথায় main-scriptহওয়া উচিত, কী testহিসাবে দেখায় $BASH_SOURCE)।

  • তাহলে sourced / মৃত্যুদন্ড কার্যকর / পড়া / evalছাড়া অন্য কোনো শেল দ্বারা ed bash, mainবলা হয় না ( BASH_SOURCEসর্বদা ভিন্ন $0)।

  • mainbashস্টিডিন থেকে স্ক্রিপ্টটি পড়লে আপনাকে ডাকা হয় না , যদি না আপনি $0খালি স্ট্রিং হিসাবে সেট না হন:( exec -a '' /bin/bash ) <script

  • যদি অন্য কোনও স্ক্রিপ্টের মধ্যে থেকে ( সমস্ত উদ্ধৃতিগুলি গুরুত্বপূর্ণ! ) bashদিয়ে মূল্যায়ন করা হয় তবে এই কলগুলি । যদি কমান্ডলাইন থেকে সরাসরি চালানো হয় তবে এটি পূর্ববর্তী ক্ষেত্রেগুলির অনুরূপ, যেখানে স্ক্রিপ্টটি স্টিডিনের কাছ থেকে পড়ে। ( ফাঁকা, যদিও সাধারণত অন্যরকম কিছু করতে বাধ্য করা হয় না))evaleval "`cat script`" mainevalBASH_SOURCE$0/bin/bash

  • যদি mainনা ডাকা হয়, এটি ফিরে আসে true( $?=0)।

  • এটি অপ্রত্যাশিত আচরণের উপর নির্ভর করে না (পূর্বে আমি অননুমোদিত লিখেছি, তবে এমন কোনও ডকুমেন্টেশনও পাইনি যা আপনি unsetপরিবর্তন করতে পারবেন না BASH_SOURCE):

    • BASH_SOURCEএকটি ব্যাশ সংরক্ষিত অ্যারে । তবে BASH_SOURCE=".$0"এটিকে পরিবর্তন করার ফলে কৃমিগুলির একটি মারাত্মক ঝুঁকিপূর্ণ দরজা খুলে যাবে, সুতরাং আমার প্রত্যাশাটি হ'ল এটির কোনও প্রভাব নেই (কেবলমাত্র, সম্ভবত, কিছু কুরুচিপূর্ণ সতর্কতা ভবিষ্যতের কিছু সংস্করণে প্রদর্শিত হবে bash)।
    • এমন কোনও ডকুমেন্টেশন নেই যা BASH_SOURCEবাইরে কাজ করে। তবে বিপরীত (এটি কেবল ফাংশনে কাজ করে) কোনওটিই নথিভুক্ত নয়। পর্যবেক্ষণটি হ'ল, এটি কাজ করে ( bashv4.3 এবং v4.4 দিয়ে পরীক্ষা করা হয়েছে , দুর্ভাগ্যক্রমে আমার bashআর v3.x নেই) এবং যে খুব বেশি স্ক্রিপ্টগুলি ভেঙে যায়, যদি $BASH_SOURCEপর্যবেক্ষণ হিসাবে কাজ করা বন্ধ করে দেয়। সুতরাং আমার প্রত্যাশাটি হ'ল এটিও BASH_SOURCEভবিষ্যতের সংস্করণগুলির মতোই রয়েছে bash
    • বিপরীতে (সুন্দর সন্ধান করুন, বিটিডাব্লু!) বিবেচনা করুন ( return 0 ), যা 0উত্সাহিত এবং 1যদি উত্সাহিত না হয় তবে দেয় । এটি কেবল আমার জন্যই কিছুটা অপ্রত্যাশিত হয়ে আসে , এবং (ওখানকার পাঠ্য অনুসারে) পসিক্স বলেছে যে returnসাবশেল থেকে অনির্ধারিত আচরণ হয় (এবং returnএখানে স্পষ্টভাবে সাবসেল থেকে এসেছে)। সম্ভবত এই বৈশিষ্ট্যটি শেষ পর্যন্ত পর্যাপ্ত পরিমাণে ব্যবহারের সুযোগ পায় যাতে এটি আর পরিবর্তন করা যায় না, তবে এএএএএফআইএসের অনেক বেশি সম্ভাবনা রয়েছে যে ভবিষ্যতের কিছু bashসংস্করণ দুর্ঘটনাক্রমে সেই ক্ষেত্রে ফিরে আসার আচরণের পরিবর্তন করে।
  • দুর্ভাগ্যক্রমে bash -x script 1 2 3চালানো হয় না main( script 1 2 3যেখানে scriptকোনও পথ নেই তার সাথে তুলনা করুন )। নিম্নলিখিতগুলি কাজের মতো হিসাবে ব্যবহার করা যেতে পারে:

    • bash -x "`which script`" 1 2 3
    • bash -xc '. script' "`which script`" 1 2 3
    • এটি bash script 1 2 3চালায় mainনা এমন একটি বৈশিষ্ট্য হিসাবে বিবেচনা করা যেতে পারে।
  • নোট করুন যে ( exec -a none script )কলগুলি main( এটি স্ক্রিপ্টে bashপাস করে না $0, এর জন্য আপনাকে -cশেষ পয়েন্টে প্রদর্শিত হিসাবে ব্যবহার করতে হবে )।

সুতরাং, কিছু কোণার কেস বাদে mainকেবল তখনই ডাকা হয়, যখন স্ক্রিপ্টটি স্বাভাবিক উপায়ে কার্যকর করা হয়। সাধারণত এটি হ'ল আপনি যা চান, বিশেষত কারণ এতে কোড বোঝার পক্ষে জটিল জটিলতা নেই।

দ্রষ্টব্য যে এটি পাইথন কোডের সাথে খুব মিল:

if __name__ == '__main__': main()

আপনি কোনও স্ক্রিনটি mainআমদানি / লোড করতে পারেন এবং এটি প্রয়োগ করতে পারেন এমন কোনও কোণার কেস ব্যতীত যা ফোন করাও বাধা দেয়__name__='__main__'

আমি কেন চ্যালেঞ্জটি সমাধান করার জন্য এটি একটি ভাল সাধারণ উপায় think

যদি আপনার কাছে এমন কিছু থাকে যা একাধিক শেল দ্বারা উত্সাহিত করা যায় তবে তা অবশ্যই সামঞ্জস্যপূর্ণ। তবে (অন্যান্য উত্তরগুলি পড়ুন), কারণ সনাক্তকরণের কোনও (কার্যকর করার সহজ) পোর্টেবল উপায় sourceনেই, আপনার নিয়মগুলি পরিবর্তন করা উচিত

এটি প্রয়োগ করে যে স্ক্রিপ্টটি অবশ্যই কার্যকর করা উচিত /bin/bash, আপনি ঠিক এটি করেন।

এটি সমস্ত ক্ষেত্রে সমাধান করে তবে নিম্নলিখিত ক্ষেত্রে স্ক্রিপ্টটি সরাসরি চলতে পারে না:

  • /bin/bash ইনস্টল বা বিযুক্ত নয় (যেমন বুট পরিবেশে ই।)
  • যদি আপনি এটির মতো কোনও শেলটি পাইপ করেন curl https://example.com/script | $SHELL
  • (দ্রষ্টব্য: এটি শুধুমাত্র সত্য যদি আপনার bashসাম্প্রতিক পর্যায়ে হয় This তবে এই রেসিপিটি কয়েকটি নির্দিষ্ট রূপের জন্য ব্যর্থ হয়েছে বলে জানা গেছে So তাই এটি নিশ্চিত হয়ে নিন যে এটি আপনার ক্ষেত্রে কার্যকর।

তবে আমি এমন কোন বাস্তব কারণ সম্পর্কে চিন্তা করতে পারি না যেখানে আপনার এটি প্রয়োজন এবং একই একই স্ক্রিপ্টকে সমান্তরালে উত্স দেওয়ার ক্ষমতাও! সাধারণত আপনি mainহাত দ্বারা চালিত করতে এটি মোড়ানো করতে পারেন । সে রকমই:

  • $SHELL -c '. script && main'
  • { curl https://example.com/script && echo && echo main; } | $SHELL
  • $SHELL -c 'eval "`curl https://example.com/script`" && main'
  • echo 'eval "`curl https://example.com/script`" && main' | $SHELL

মন্তব্য

  • এই উত্তরটি অন্য সমস্ত উত্তরগুলির সাহায্য ছাড়া সম্ভব হত না! এমনকি ভুলগুলিও - যা প্রাথমিকভাবে আমাকে এটি পোস্ট করে।

  • আপডেট: https://stackoverflow.com/a/28776166/490291 এ পাওয়া নতুন আবিষ্কারের কারণে সম্পাদিত


Ksh এবং bash-4.3 এর জন্য পরীক্ষিত। খুশী হলাম। এটি এমন করুণভাবে আপনার উত্তরটির পক্ষে একটি কঠিন জীবন থাকবে যা অন্য উত্তরগুলিতে ইতিমধ্যে বহু বছর ধরে ভোট সংগ্রহ করা ছিল।
হেগেলো

এই উত্তরের জন্য আপনাকে ধন্যবাদ। আমি যদি আইএফ স্টেটমেন্টটির সাথে দীর্ঘতর, 'কম পঠনযোগ্য' পরীক্ষার প্রশংসা করি কারণ কমপক্ষে নিঃশব্দ ব্যর্থতা দিতে উভয় পরিস্থিতি পরিচালনা করা ভাল nice আমার ক্ষেত্রে আমার কোনও স্ক্রিপ্ট দরকার তা উত্সাহিত করতে বা অন্যথায় উত্সটি ব্যবহার না করে তাদের ত্রুটি সম্পর্কে ব্যবহারকারীকে অবহিত করতে হবে।
টিম রিচার্ডসন

@ টিনো: যেমনটি "বিভিন্ন শাঁস দ্বারাও উত্সাহিত হতে পারে": ম্যাকোজে, যেখানে /bin/shকার্যকরভাবে bashপসিক্স মোডে রয়েছে, আপনার স্ক্রিপ্টটি BASH_SOURCE ভেঙে দেওয়ার জন্য বরাদ্দ দেওয়া হয়েছে । অন্যান্য শাঁস ইন ( dash, ksh, zsh), একটি ফাইল আর্গুমেন্ট হিসাবে এটি ক্ষণস্থায়ী দ্বারা আপনার স্ক্রিপ্টটি invoking শেল এক্সিকিউটেবল সরাসরি চলমান সমস্যা (যেমন, zsh <your-script>আপনার স্ক্রিপ্ট ভুল করে মনে হয় এটা করতে হবে sourced )। (আপনি ইতিমধ্যে যে উল্লেখ বংশীধ্বনিতুল্য কোড চলমান সমস্যা, সমস্ত শাঁস মধ্যে।)
mklement0

@ টিনো: একপাশে: যদিও . <your-script>( স্রোসিং ) নীতিগতভাবে সমস্ত পসিক্সের মতো শেলগুলি থেকে কাজ করে তবে এটি কেবল তখনই বোধগম্য হয় যখন স্ক্রিপ্টটি স্পষ্টভাবে কেবল পসিক্স বৈশিষ্ট্যগুলি ব্যবহার করার জন্য লেখা হয়েছিল, যাতে একটি শেলের সাথে সম্পর্কিত বৈশিষ্ট্যগুলি কার্যকর করতে না দেওয়া থেকে বিরত রাখা যায় অন্যান্য শেল মধ্যে; বাশ শেবাং লাইন ব্যবহার করা (এর পরিবর্তে #!/bin/sh) তাই বিভ্রান্তিকর - অন্তত একটি স্পষ্ট মন্তব্য ছাড়াই। বিপরীতভাবে, যদি আপনার স্ক্রিপ্টটি কেবল বাশ থেকে চালানো বোঝানো হয় (এমনকি কী বৈশিষ্ট্যগুলি পোর্টেবল হতে পারে না তা বিবেচনা করার কারণেও), নন-ব্যাশ শেলগুলিতে মৃত্যুদন্ড কার্যকর করা অস্বীকার করা ভাল better
mklement0

1
@ mklement0 আবার ধন্যবাদ, একটি নোট যুক্ত করুন যে এখানে একটি সমস্যা আছে। অন্যান্য পাঠকদের জন্য: বাশ v3.x দিয়ে সস করা হলে এটি কার্যকর করা উচিত নয় main, তবে এটি এই ক্ষেত্রে এটি করে! এবং যখন উত্সাহিত হয় /bin/sh, যা bash --posixএই ক্ষেত্রে একই ঘটে এবং এটিও স্পষ্টত ভুল।
টিনো

6

এটি পরে স্ক্রিপ্টে কাজ করে এবং _ ভেরিয়েবলের উপর নির্ভর করে না:

## Check to make sure it is not sourced:
Prog=myscript.sh
if [ $(basename $0) = $Prog ]; then
   exit 1  # not sourced
fi

অথবা

[ $(basename $0) = $Prog ] && exit

1
আমি মনে করি এই উত্তরটি এখানে কয়েকটি পসিক্সের অনুগত of সুস্পষ্ট ডাউনসাইডস হওয়ায় আপনাকে ফাইলের নামটি জানতে হবে এবং উভয় স্ক্রিপ্টে একই ফাইলের নাম থাকলে এটি কাজ করে না।
জেপিজেড

5

আমি একটি বেস-নির্দিষ্ট উত্তর দেব give জন্মের শেল, দুঃখিত। মনে করুন আপনার স্ক্রিপ্টের নাম include2.sh; তারপর একটি ফাংশন করতে ভিতরেinclude2.sh নামক am_I_sourced। এখানে আমার ডেমো সংস্করণ include2.sh:

am_I_sourced()
{
  if [ "${FUNCNAME[1]}" = source ]; then
    if [ "$1" = -v ]; then
      echo "I am being sourced, this filename is ${BASH_SOURCE[0]} and my caller script/shell name was $0"
    fi
    return 0
  else
    if [ "$1" = -v ]; then
      echo "I am not being sourced, my script/shell name was $0"
    fi
    return 1
  fi
}

if am_I_sourced -v; then
  echo "Do something with sourced script"
else
  echo "Do something with executed script"
fi

এখন এটি বিভিন্ন উপায়ে কার্যকর করার চেষ্টা করুন:

~/toys/bash $ chmod a+x include2.sh

~/toys/bash $ ./include2.sh 
I am not being sourced, my script/shell name was ./include2.sh
Do something with executed script

~/toys/bash $ bash ./include2.sh 
I am not being sourced, my script/shell name was ./include2.sh
Do something with executed script

~/toys/bash $ . include2.sh
I am being sourced, this filename is include2.sh and my caller script/shell name was bash
Do something with sourced script

সুতরাং এটি ব্যতিক্রম ছাড়াই কাজ করে এবং এটি ভঙ্গুর $_স্টাফ ব্যবহার করে না । এই কৌশলটি BASH- র অন্তর্নির্মাণ সুবিধা ব্যবহার করে, যেমন বিল্ট-ইন ভেরিয়েবল FUNCNAMEএবং BASH_SOURCE; বাশ ম্যানুয়াল পৃষ্ঠাতে তাদের ডকুমেন্টেশন দেখুন।

মাত্র দুটি সতর্কতা:

1) কলে am_I_called আবশ্যক সঞ্চালিত মধ্যে সোর্সড স্ক্রিপ্ট, কিন্তু মধ্যে না কোনো ফাংশন, পাছে ${FUNCNAME[1]}অন্য আয় কিছু। হ্যাঁ ... আপনি পরীক্ষা করতে পারতেন ${FUNCNAME[2]}- তবে আপনি নিজের জীবনকে আরও শক্ত করে তোলেন।

2) ফাংশনটি am_I_called অবশ্যই উত্সযুক্ত স্ক্রিপ্টে থাকা উচিত যদি আপনি ফাইলটির নাম অন্তর্ভুক্ত করা হচ্ছে তা জানতে চান।


1
স্পেসিফিকেশন: এই বৈশিষ্ট্যটির কাজ করতে BASH সংস্করণ 3+ প্রয়োজন। বেস 2 এ, FUNCNAME হ'ল অ্যারের পরিবর্তে একটি স্কেলার ভেরিয়েবল। এছাড়াও বেস 2 তে BASH_SOURCE অ্যারে ভেরিয়েবল নেই।
বীরাওয়ান পূর্বন্তো

4

আমি ডেনিসের খুব সহায়ক উত্তরের জন্য একটি ছোট সংশোধন সুপারিশ করতে চাই , এটি আরও কিছুটা পোর্টেবল করার জন্য, আমি আশা করি:

[ "$_" != "$0" ] && echo "Script is being sourced" || echo "Script is a subshell"

কারণ [[(কিছুটা এনাল রিটেনটিভ আইএমএইচও) দেবিয়ান পসিক্স সামঞ্জস্যপূর্ণ শেল, দ্বারা স্বীকৃত নয় dash। এছাড়াও, শেলটিতে আবারও ফাঁকা থাকা ফাইলনামগুলির বিরুদ্ধে সুরক্ষার জন্য কারও কাছে উদ্ধৃতিগুলির প্রয়োজন হতে পারে।


2

$_বেশ ভঙ্গুর। আপনি এটি স্ক্রিপ্টে প্রথম কাজ হিসাবে পরীক্ষা করে দেখতে হবে। এবং তারপরেও, আপনার শেলের নাম (যদি তা উত্সাহিত হয়) বা স্ক্রিপ্টের নাম (যদি মৃত্যুদণ্ড কার্যকর করা হয়) ধারণ করার নিশ্চয়তা নেই।

উদাহরণস্বরূপ, যদি ব্যবহারকারী সেট করে থাকে BASH_ENV, তবে স্ক্রিপ্টের শীর্ষে, স্ক্রিপ্টে $_সম্পাদিত শেষ কমান্ডের নাম থাকে BASH_ENV

আমি সবচেয়ে ভাল উপায় খুঁজে পেয়েছি এটি ব্যবহার করা হয় $0:

name="myscript.sh"

main()
{
    echo "Script was executed, running main..."
}

case "$0" in *$name)
    main "$@"
    ;;
esac

দুর্ভাগ্যক্রমে, এই functionargzeroনামটি zsh এর বাক্সের বাইরে চলে যায় না কারণ বিকল্প নাম এর প্রস্তাব অনুযায়ী বেশি করে, এবং ডিফল্টরূপে থাকে।

এটি প্রায় কাজ করতে, আমি unsetopt functionargzeroআমার মধ্যে রাখা .zshenv


1

আমি mklement0 কমপ্যাক্ট এক্সপ্রেশন অনুসরণ করেছি

এটি ঝরঝরে, তবে আমি লক্ষ্য করেছি যে ksh এর ক্ষেত্রে এটি ব্যর্থ হতে পারে যখন এটি হিসাবে ডাকা হয়:

/bin/ksh -c ./myscript.sh

(এটি মনে করে এটি সসেট হয়েছে এবং এটি সাবসেল কার্যকর করার কারণে নয়) তবে অভিব্যক্তি এটি সনাক্ত করতে কাজ করবে:

/bin/ksh ./myscript.sh

এছাড়াও, অভিব্যক্তিটি সংক্ষিপ্ত হলেও সিনট্যাক্সটি সমস্ত শেলের সাথে সামঞ্জস্যপূর্ণ নয়।

সুতরাং আমি নিম্নলিখিত কোডটি দিয়ে শেষ করেছি, যা ব্যাশ, জেডএস, ড্যাশ এবং ক্যাসের জন্য কাজ করে

SOURCED=0
if [ -n "$ZSH_EVAL_CONTEXT" ]; then 
    [[ $ZSH_EVAL_CONTEXT =~ :file$ ]] && SOURCED=1
elif [ -n "$KSH_VERSION" ]; then
    [[ "$(cd $(dirname -- $0) && pwd -P)/$(basename -- $0)" != "$(cd $(dirname -- ${.sh.file}) && pwd -P)/$(basename -- ${.sh.file})" ]] && SOURCED=1
elif [ -n "$BASH_VERSION" ]; then
    [[ $0 != "$BASH_SOURCE" ]] && SOURCED=1
elif grep -q dash /proc/$$/cmdline; then
    case $0 in *dash*) SOURCED=1 ;; esac
fi

বহিরাগত শেল সমর্থন যোগ করুন নির্দ্বিধায় :)


ইন ksh 93+u, ksh ./myscript.shআমার পক্ষে কাজ করে (আমার বক্তব্য সহ) - আপনি কোন সংস্করণ ব্যবহার করছেন?
এমকিলেমেন্ট 0

আমি আশঙ্কা করি যে নির্ভরযোগ্যভাবে নির্ধারণের কোনও উপায় নেই যদি স্ক্রিপ্টটি কেবল পসিক্স-বৈশিষ্ট্যগুলি ব্যবহার করে তৈরি করা হয়: আপনার প্রচেষ্টা লিনাক্সকে ধরে নিয়েছে ( /proc/$$/cmdline) এবং dashকেবলমাত্র (যা shউদাহরণস্বরূপ উবুন্টুতেও কাজ করে) উপর দৃষ্টি নিবদ্ধ করে । আপনি যদি কিছু অনুমান করতে ইচ্ছুক হন তবে আপনি $0একটি যুক্তিসঙ্গত - তবে অসম্পূর্ণ - পরীক্ষাটি পরীক্ষাযোগ্য যা বহনযোগ্য।
mklement0

++ বেসিক পদ্ধতির জন্য, যদিও - আমি আমার উত্তরের একটি সংযোজন হিসাবে , সমর্থন করি sh/ dashসেইসাথে সমর্থন দেওয়ার সর্বোত্তম পোর্টেবল অনুমান যা বলে মনে করি তার জন্য এটি খাপ খাইয়ে নিতে আমি স্বাধীনতা নিয়েছি ।
mklement0

0

Ksh এবং bash উভয় ক্ষেত্রে এটি করার কোনও পোর্টেবল উপায় আছে বলে আমি মনে করি না। ব্যাশে আপনি callerআউটপুট ব্যবহার করে এটি সনাক্ত করতে পারেন , তবে আমি মনে করি না যে ksh এর সমতুল্য রয়েছে।


$0কাজ করে bash, ksh93এবং pdksh। আমার নেইksh88 পরীক্ষা দিতে ।
মাইকেল

0

আমার একটি ওয়ান-লাইনার দরকার ছিল যা bash.version> = 3 সহ [ম্যাক, লিনাক্স] এ কাজ করে এবং এর উত্তরগুলির কোনওটিরও বিলের সাথে মানানসই নয়।

[[ ${BASH_SOURCE[0]} = $0 ]] && main "$@"

1
bashসমাধান ভাল কাজ করে (আপনাকে প্রক্রিয়া সহজ পারে $BASH_SOURCE), কিন্তু kshসমাধান শক্তসমর্থ: যদি আপনার স্ক্রিপ্টটি দ্বারা sourced হচ্ছে অন্য স্ক্রিপ্ট , আপনি একটি মিথ্যা ইতিবাচক পাবেন।
mklement0

0

সোজা বিন্দু: পরিবর্তনশীল আপনার মূল্যায়ন করতে হবে " শেল " এর নামের সাথে "$ 0" সমান ।


এটার মত:

#!/bin/bash

echo "First Parameter: $0"
echo
if [[ "$0" == "bash" ]] ; then
    echo "The script was sourced."
else
    echo "The script WAS NOT sourced."
fi


বিক্রয় মাধ্যমে :

$ bash check_source.sh 
First Parameter: check_source.sh

The script WAS NOT sourced.

উত্স মাধ্যমে :

$ source check_source.sh
First Parameter: bash

The script was sourced.



এটি একটি খুব কঠিন কোনও স্ক্রিপ্ট উত্সাহিত হয়েছিল কিনা তা সনাক্ত করার 100% বহনযোগ্য উপায়টি পাওয়া ।

আমার অভিজ্ঞতা সম্পর্কে (শেলসক্রিপ্টিং সহ 7 বছর) , একমাত্র নিরাপদ উপায় ( পিআইডি সহ পরিবেশের ভেরিয়েবলের উপর নির্ভর না করা ইত্যাদি) যা নিরাপদ নয় যে এটি কিছু হওয়ার কারণে পরিবর্তনশীল ), আপনি উচিত:

  • আপনার যদি থেকে সম্ভাবনা প্রসারিত
  • আপনি যদি চান, স্যুইচ / কেস ব্যবহার করে।

উভয় বিকল্প স্বয়ংক্রিয়ভাবে মাপানো যাবে না, তবে এটি নিরাপদ উপায়।



উদাহরণ স্বরূপ:

যখন আপনি এসএসএইচ সেশনের মাধ্যমে কোনও স্ক্রিপ্ট উত্স করেন, তখন "$ 0" ভেরিয়েবল ( উত্স ব্যবহার করার সময় ) দ্বারা প্রত্যাবর্তিত মানটি হ'ল -বাশ

#!/bin/bash

echo "First Parameter: $0"
echo
if [[ "$0" == "bash" || "$0" == "-bash" ]] ; then
    echo "The script was sourced."
else
    echo "The script WAS NOT sourced."
fi

অথবা

#!/bin/bash

echo "First Parameter: $0"
echo
if [[ "$0" == "bash" ]] ; then
    echo "The script was sourced."
elif [[ "$0" == "-bash" ]] ; then
    echo "The script was sourced via SSH session."
else
    echo "The script WAS NOT sourced."
fi

2
, Downvoted হিসাবে এই সমভূমি ভুল: /bin/bash -c '. ./check_source.sh'দেয় The script WAS NOT sourced.। একই বাগ: ln -s /bin/bash pumuckl; ./pumuckl -c '. ./check_source.sh'->The script WAS NOT sourced.
টিনো

2
আপনার ডাউনভোট পুরো দৃশ্যপট পরিবর্তন করেছে এবং একটি দুর্দান্ত অবদান রেখেছেন, টিনো। ধন্যবাদ!
ivanleoncz

0

আমি চেক দিয়ে শেষ [[ $_ == "$(type -p "$0")" ]]

if [[ $_ == "$(type -p "$0")" ]]; then
    echo I am invoked from a sub shell
else
    echo I am invoked from a source command
fi

curl ... | bash -s -- ARGSঅন ​​ফ্লাইতে রিমোট স্ক্রিপ্ট চালানোর জন্য যখন ব্যবহার করবেন, আসল স্ক্রিপ্ট ফাইল চালানোর সময় the 0 bashস্বাভাবিকের পরিবর্তে /bin/bashহবে, তাই আমি ব্যবহার করিtype -p "$0" ব্যাশের পুরো পথটি দেখানোর জন্য ।

পরীক্ষা:

curl -sSL https://github.com/jjqq2013/bash-scripts/raw/master/common/relpath | bash -s -- /a/b/c/d/e /a/b/CC/DD/EE

source <(curl -sSL https://github.com/jjqq2013/bash-scripts/raw/master/common/relpath)
relpath /a/b/c/d/e /a/b/CC/DD/EE

wget https://github.com/jjqq2013/bash-scripts/raw/master/common/relpath
chmod +x relpath
./relpath /a/b/c/d/e /a/b/CC/DD/EE

0

এটি "সার্বজনীন" ক্রস শেল সমর্থন সম্পর্কিত, অন্য কয়েকটি উত্তর থেকে একটি স্পিন অফ। এটি স্বতঃস্ফূর্তভাবে কিছুটা আলাদা হলেও https://stackoverflow.com/a/2942183/3220983 এর সাথে খুব মিল রয়েছে similar এর সাথে দুর্বলতা হ'ল কোনও ক্লায়েন্ট স্ক্রিপ্টকে অবশ্যই এটি কীভাবে ব্যবহার করবেন তা বোঝাতে হবে (অর্থাত্ প্রথমে একটি পরিবর্তনশীল রফতানি করে)। শক্তিটি হ'ল এটি সহজ এবং "যে কোনও জায়গায়" কাজ করা উচিত। আপনার কাটা এবং পেস্ট আনন্দের জন্য এখানে একটি টেম্পলেট রয়েছে:

# NOTE: This script may be used as a standalone executable, or callable library.
# To source this script, add the following *prior* to including it:
# export ENTRY_POINT="$0"

main()
{
    echo "Running in direct executable context!"
}

if [ -z "${ENTRY_POINT}" ]; then main "$@"; fi

দ্রষ্টব্য: আমি exportনিশ্চিত নিশ্চিত ব্যবহার করি যে এই প্রক্রিয়াটি উপ-প্রক্রিয়াগুলিতে প্রসারিত হতে পারে।

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