मुझे कैसे पता चलेगा कि कुछ बैश फ़ंक्शन कहाँ परिभाषित है?


28

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


जवाबों:


32

डिबगिंग चालू करें। से बैश मैनुअल :

extdebug

यदि शेल इनवॉइस, या शेल स्टार्टअप फ़ाइल में सेट किया गया है, तो शेल के शुरू होने से पहले डिबगर प्रोफ़ाइल को निष्पादित करने की व्यवस्था करें, --debuggerविकल्प के समान । यदि आह्वान के बाद सेट किया जाता है, तो डिबगर्स द्वारा उपयोग किए जाने वाले व्यवहार को सक्षम किया जाता है:

  • बिलिन का -Fविकल्प declare( बैश बिल्डिंस देखें ) एक तर्क के रूप में दिए गए प्रत्येक फ़ंक्शन नाम के अनुरूप स्रोत फ़ाइल नाम और लाइन नंबर प्रदर्शित करता है।

उदाहरण:

$ bash --debugger
$ declare -Ff quote
quote 143 /usr/share/bash-completion/bash_completion

और सचमुच में:

$ nl -ba /usr/share/bash-completion/bash_completion | sed -n 143,150p
   143  quote()
   144  {
   145      local quoted=${1//\'/\'\\\'\'}
   146      printf "'%s'" "$quoted"
   147  }
   148
   149  # @see _quote_readline_by_ref()
   150  quote_readline()

यह एक बेहतरीन और सरल उपाय है। आपके उदाहरण के लिए, एक नया शेल शुरू करने की भी आवश्यकता नहीं है shopt -s extdebug; declare -Ff quote; shopt -u extdebug:।
जर्नो

2
@ कर्णो आह, ठीक है, मेरे नाम के विपरीत, मैं zsh का उपयोग करता हूं। इसलिए मैंने एक नया खोल शुरू किया। : D
बैशिटी mcbashface

क्या उर्फ घोषणा स्थानों को खोजने के लिए एक समान विधि है ?
फेडनकादिफ़ेली

@ मेरे दृढ़ और जटिल दृष्टिकोण के नीचे काम करना चाहिए।
टेराडो

1
आप इसे इस तरह से बना सकते हैं find_function()( shopt -s extdebug; declare -F "$@"; ):। फ़ंक्शन बॉडी पर पार्न्स के साथ, यह एक सब-डिले में निष्पादित हो जाता है और शॉपर्स में परिवर्तन कॉलर को प्रभावित नहीं करता है। और -fजरूरत नहीं लगती।
wjandrea

15

यह वास्तव में पहले की तुलना में अधिक जटिल है। आपके शेल द्वारा कौन सी फाइलें पढ़ी जाती हैं यह इस बात पर निर्भर करता है कि आप वर्तमान में किस प्रकार के शेल में चल रहे हैं। यह इंटरएक्टिव है या नहीं, यह लॉगिन है या नॉन-लॉगिन शेल है और ऊपर का क्या संयोजन है। विभिन्न शेल द्वारा पढ़ी जा सकने वाली सभी डिफ़ॉल्ट फ़ाइलों के माध्यम से खोज करने के लिए, आप कर सकते हैं ( $functionNameजिस फ़ंक्शन को आप देख रहे हैं उसके वास्तविक नाम में परिवर्तन करें):

grep "$functionName" ~/.bashrc ~/.profile ~/.bash_profile ~/.bash.login \
                     ~/.bash_aliases /etc/bash.bashrc /etc/profile \
                     /etc/profile.d/* /etc/environment 2> /dev/null

यदि वह काम नहीं करता है, तो आप एक गैर-डिफ़ॉल्ट फ़ाइल का उपयोग करके .या उसके उपनाम से कॉल कर सकते हैं source। ऐसे मामलों को खोजने के लिए, दौड़ें:

grep -P '(^|\s)(\.|source)\s+' ~/.bashrc ~/.profile ~/.bash_profile \
                               ~/.bash.login ~/.bash_aliases /etc/bash.bashrc \
                               /etc/profile /etc/profile.d/* /etc/environment 2> /dev/null

शायद कुछ स्पष्टीकरण की जरूरत है। -Pपर्ल कम्पैटिबल रेगुलर एक्सप्रेशन (PCRE) जो हमें कुछ अधिक सजावटी regex सिंटैक्स का उपयोग सक्षम बनाता है। विशेष रूप से:

  • (^|\s): या तो एक पंक्ति ( ^) या व्हाट्सएप ( \s) की शुरुआत से मेल खाता है ।
  • (\.|source)\s+: या तो एक शाब्दिक .चरित्र ( \.) या शब्द से मेल खाते हैं source, लेकिन केवल अगर वे एक या एक से अधिक व्हाट्सएप वर्णों का पालन करते हैं।

यहाँ है जो मुझे अपने सिस्टम पर देता है:

$ grep -P '(^|\s)(\.|source)\s+' ~/.bashrc ~/.profile ~/.bash_profile \
>                                ~/.bash.login ~/.bash_aliases /etc/bash.bashrc \
>                                /etc/profile /etc/profile.d/* /etc/environment 2> /dev/null
/home/terdon/.bashrc:   . /etc/bashrc
/home/terdon/.bashrc:   . /etc/bash_completion
/home/terdon/.bashrc:. $HOME/scripts/git-prompt.sh
/home/terdon/.bashrc:#  echo -n "$n : "; grep "^CA"  $n |perl -e 'my ($a,$c)=0; while(<>){$c++;next if /cellular_component_unknown/; next if /biological_process/; $a++} print "$a Classes of $c annotated (" . $a*100/$c . ")\n"' 
/etc/bash.bashrc:[ -r /usr/share/bash-completion/bash_completion   ] && . /usr/share/bash-completion/bash_completion
/etc/profile:       test -r "$profile" && . "$profile"
/etc/profile:   . /etc/bash.bashrc
/etc/profile.d/locale.sh:    . "$XDG_CONFIG_HOME/locale.conf"
/etc/profile.d/locale.sh:    . "$HOME/.config/locale.conf"
/etc/profile.d/locale.sh:    . /etc/locale.conf
/etc/profile.d/Z97-byobu.sh:        . /usr/bin/byobu-launch
/etc/profile.d/Z97-byobu.sh:        . /usr/bin/byobu-launch
/etc/profile.d/Z97-byobu.sh:        . /usr/bin/byobu-launch
/etc/profile.d/Z97-byobu.sh:        . /usr/bin/byobu-launch
/etc/profile.d/Z97-byobu.sh:        . /usr/bin/byobu-launch

जैसा कि आप देख सकते हैं, हालांकि, यह पूरी मिलान रेखा को प्रिंट करेगा। हम वास्तव में जिस चीज में रुचि रखते हैं वह फाइल नामों की सूची है, न कि उन्हें कॉल करने वाली रेखा। आप इसके साथ उन लोगों को प्राप्त कर सकते हैं, अधिक जटिल, regex:

grep -hPo '(^|\s)(\.|source)\s+\K\S+' ~/.bashrc ~/.profile ~/.bash_profile \
                                      ~/.bash.login ~/.bash_aliases \
                                      /etc/bash.bashrc /etc/profile \
                                      /etc/profile.d/* /etc/environment 2> /dev/null

-hझंडा फ़ाइल नाम जहां एक मैच मिला था, जिनमें से मुद्रण को दबा grepजब एक से अधिक फ़ाइलों के माध्यम से खोज करने के लिए कहा था कि डिफ़ॉल्ट रूप से करता है। इसका -oमतलब है "केवल रेखा के मिलान वाले भाग को प्रिंट करें"। Regex में जोड़े गए अतिरिक्त सामान हैं:

  • \K: इस बिंदु तक कुछ भी अनदेखा करें। यह एक पीसीआरई ट्रिक है जिससे आप अपने मैच को ढूंढने के लिए एक जटिल रीगेक्स का उपयोग कर सकते हैं लेकिन उस मिलान वाले हिस्से को शामिल न करें जब grep के -oझंडे का उपयोग करें ।

मेरे सिस्टम पर, उपरोक्त कमांड वापस आ जाएगी:

$ grep -hPo '(^|\s)(\.|source)\s+\K\S+' ~/.bashrc ~/.profile ~/.bash_profile \
>                                       ~/.bash.login ~/.bash_aliases \
>                                       /etc/bash.bashrc /etc/profile \
>                                       /etc/profile.d/* /etc/environment 2> /dev/null
/etc/bashrc
/etc/bash_completion
$HOME/scripts/git-prompt.sh
$a*100/$c
")\n"'
/usr/share/bash-completion/bash_completion
"$profile"
/etc/bash.bashrc
"$XDG_CONFIG_HOME/locale.conf"
"$HOME/.config/locale.conf"
/etc/locale.conf
/usr/bin/byobu-launch
/usr/bin/byobu-launch
/usr/bin/byobu-launch
/usr/bin/byobu-launch
/usr/bin/byobu-launch

ध्यान दें कि मेरे पास एक .स्थान का उपयोग करने के लिए है जो कि सोर्सिंग के लिए उपयोग नहीं किया जाता है, लेकिन ऐसा इसलिए है क्योंकि मेरे पास एक उपनाम है जो किसी अन्य भाषा को कॉल कर रहा है, बैश नहीं। जो अजीब $a*100/$cऔर ")\n"'ऊपर के आउटपुट में देता है। लेकिन इसे नजरअंदाज किया जा सकता है।

अंत में, यहां बताया गया है कि सभी को एक साथ कैसे रखा जाए और सभी डिफ़ॉल्ट फ़ाइलों में एक फ़ंक्शन नाम की खोज करें और सभी फाइलें आपकी डिफ़ॉल्ट फ़ाइलों को सोर्स कर रही हैं:

grep_function(){
  target="$@"
  files=( ~/.bashrc ~/.profile ~/.bash_profile ~/.bash.login 
         ~/.bash_aliases /etc/bash.bashrc /etc/profile 
         /etc/profile.d/* /etc/environment)
    while IFS= read -r file; do
      files+=( "$file" )
    done < <(grep -hPo '(^|\s)(\.|source)\s+\K\S+'  "${files[@]}" 2>/dev/null)
    for file in "${files[@]}"; do
      ## The tilde of ~/ can break this
      file=$(sed 's|~/|'"$HOME"'/|g' <<<"$file")
      if [[ -e $file ]]; then
        grep -H "$target" -- "$file"
      fi
    done
}

उन पंक्तियों को अपने साथ जोड़ें ~/.bashrcऔर फिर आप चला सकते हैं (मैं fooBarएक उदाहरण फ़ंक्शन नाम के रूप में उपयोग कर रहा हूं ):

grep_function fooBar

उदाहरण के लिए, यदि मेरे पास यह रेखा है ~/.bashrc:

. ~/a

और फाइल ~/aहै:

$ cat ~/a
fooBar(){
  echo foo
}

मुझे इसे ढूंढना चाहिए:

$ grep_function fooBar
/home/terdon/a:fooBar(){

आपका समाधान एक महान शैक्षिक स्क्रिप्टिंग उदाहरण है, लेकिन मुझे बैशिटी mcbashface का समाधान सरल लगता है।
जर्नो

@ कर्नो और यह बहुत, बहुत सरल है! :)
टेराडो

एरे का समर्थन+=
डी। बेन नोबल

@ D.BenKnoble वे करते हैं? आप सरणी के 1 तत्व के लिए array+="foo"स्ट्रिंग fooको जोड़ने के अलावा अन्य मतलब है ?
टेराडन

1
@ D.BenKnoble धन्यवाद! मैं नहीं जानता कि बैश सरणियों ने उस संकेतन का समर्थन किया!
टेराडन

2

हमेशा की तरह प्रति-उपयोगकर्ता dotfile bashपढ़ता है ~/.bashrc। हालाँकि, यह अन्य फ़ाइलों को बहुत अच्छी तरह से स्रोत कर सकता है, उदाहरण के लिए, मैं अलग-अलग फ़ाइलों में उपनामों और कार्यों को रखना पसंद करता हूं ~/.bash_aliasesऔर ~/.bash_functions, जो उन्हें बहुत आसान बनाता है। आप निम्न आदेशों के .bashrcलिए खोज कर सकते हैं source:

grep -E '(^\s*|\s)(\.|source)\s' /home/USERNAME/.bashrc

एक बार आपके पास उपयोगकर्ता द्वारा बनाई गई फ़ाइलों की सूची है, तो आप उन्हें और उपयोगकर्ता .bashrcको एक grepकॉल के साथ खोज सकते हैं , उदाहरण के fooलिए मेरे सेटअप के लिए कार्य :

grep foo /home/USERNAME/.bash{rc,_aliases,_functions}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.