Belirli bash fonksiyonunun tanımlandığı yeri nasıl bulabilirim?


Yanıtlar:


32

Hata ayıklamayı aç. Gönderen Bash kılavuzda :

extdebug

Kabuk çağırmada veya bir kabuk başlangıç ​​dosyasında ayarlanmışsa, kabuk başlamadan önce, --debuggerseçeneğe benzer hata ayıklayıcı profilini yürütmek için düzenleme yapın . Çağrının ardından ayarlanırsa, hata ayıklayıcıların kullanması amaçlanan davranış etkindir:

  • -FSeçeneği declareyerleşiğini (bkz Bash çıkmasını sağlamakta ) bir argüman olarak verilen her işlev adına karşılık gelen kaynak dosya adı ve satır sayısını gösterir.

Örnek:

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

Ve gerçekten:

$ 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()

Bu harika ve basit bir çözüm. Senin Örneğin gelince, o bile yeni bir kabuk başlatmak için gerekli değildir: shopt -s extdebug; declare -Ff quote; shopt -u extdebug.
jarno

2
@ jarno ah, iyi, ismimin aksine, zsh kullanıyorum. Bu yüzden yeni bir kabuk başlattım. : D
bashity mcbashface

Takma ad bildirme konumlarını bulmak için benzer bir yöntem var mı ?
FedonKadifeli

fedon, aşağıdaki kıvrımlı ve karmaşık yaklaşımım işe yaramalı.
terdon

1
Bu böyle bir fonksiyon yapabilir: find_function()( shopt -s extdebug; declare -F "$@"; ). Fonksiyon gövdesindeki parens ile, bir alt kabukta yürütülür ve dükkandaki değişiklik arayanı etkilemez. Ve bu -fgerekli görünmüyor.
wjandrea,

15

Bu aslında ilk başta göründüğünden daha karmaşık. Hangi dosyalar kabuğunuz tarafından okunur , şu anda ne tür bir kabuk çalıştırdığınıza bağlıdır. Etkileşimli olup olmadığına bakılmaksızın, bir giriş mi yoksa giriş olmayan bir kabuk mu ve yukarıdakilerin bir kombinasyonu. Farklı mermiler tarafından okunabilen tüm varsayılan dosyaları aramak için şunları yapabilirsiniz ( $functionNamearadığınız işlevin asıl adını değiştirin ):

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

Bu işe yaramazsa, varsayılan olmayan bir dosyayı .ya da diğer adını kullanarak çağırıyor olabilirsiniz source. Bu tür vakaları bulmak için koşun:

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

Bu muhtemelen biraz açıklama gerektiriyor. -PBize biraz daha süslü regex sözdizimi kullanmasına izin Perl Uyumlu Normal İfadeler (PCRE) sağlar. özellikle:

  • (^|\s): bir satırın başlangıcıyla ( ^) veya boşlukla ( \s) eşleşir .
  • (\.|source)\s+: değişmez .karakter ( \.) veya sözcüğü eşleştirin source, ancak yalnızca bir veya daha fazla boşluk karakteri izlerse eşleştirin .

İşte benim sistemimde bana ne veriyor:

$ 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

Gördüğünüz gibi, bu, eşleşen çizginin tamamını basacaktır. Gerçekten ilgilendiğimiz şey, onları çağıran satırı değil, adı verilen dosya adlarının listesidir. Bunları daha karmaşık, regex ile alabilirsiniz:

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

-hBayrak bir eşleşme bulunmuştur dosya adları, basılmasını bastırır grepbirden fazla dosya üzerinden arama için söylendi varsayılan olarak yapar. -oVasıta "sadece hattının eşleşen bölümünü yazdırmak". Regex'e eklenen fazladan şeyler:

  • \K: bu noktaya uyan her şeyi görmezden gelin. Bu, eşinizi bulmak için karmaşık bir regex kullanmanıza izin veren, ancak grep'in -obayrağını kullanırken eşleşen kısmı içermeyen PCRE numarasıdır .

Sistemimde yukarıdaki komut dönecektir:

$ 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

Ben bir kullanımı için gerçekleştiğini Not .edilir ve ardından bir boşluk değil ben başka bir dil değil, bash aradığını bir takma adı var çünkü kaynak için kullanılan ama bu 's. Garip $a*100/$cve ")\n"'yukarıdaki çıktıda veren budur . Ancak bu göz ardı edilebilir.

Son olarak, tüm bunların bir araya getirilmesi ve tüm varsayılan dosyalarda ve varsayılan dosyalarınızın kaynak olduğu tüm dosyalarda bir işlev adı aranması :

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
}

Bu satırları kendinize ekleyin ~/.bashrcve sonra çalıştırabilirsiniz ( fooBarÖrnek bir işlev adı olarak kullanıyorum ):

grep_function fooBar

Örneğin, bu çizgiyi benim yerimde varsa ~/.bashrc:

. ~/a

Ve dosya ~/a:

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

Şunu bulmalıyım:

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

Çözümünüz harika bir eğitim senaryosu örneği, ancak ben bashity mcbashface'in çözümünü daha basit buluyorum.
jarno

@ jarno ve çok, çok daha basit! :)
terdon

Diziler desteği+=
D. Ben Knoble

@ D.BenKnoble onlar mı? Diziyi dizinin ilk elemanına array+="foo"eklemekten başka foo?
terdon

1
@ D.BenKnoble teşekkürler! Bash dizilerinin bu gösterimi desteklediğini bilmiyordum!
terdon

2

Her zamanki dotfile başına kullanıcı bashokur olduğunu ~/.bashrc. Denilen ayrı dosyalarda takma adları ve işlevleri tutmak gibi Ancak, çok iyi örneğin I diğer dosyaları kaynak oluşturabileceği ~/.bash_aliasesve ~/.bash_functionsdaha kolay onları bulmasını sağlar. .bashrcFor sourcekomutlarını aşağıdakilerle arayabilirsiniz :

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

Kullanıcı tarafından oluşturulan dosyalar listesine sahip olduktan sonra, onları ve kullanıcıyı .bashrctek bir greparama ile arayabilirsiniz, örneğin fookurulumumun işlevi için:

grep foo /home/USERNAME/.bash{rc,_aliases,_functions}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.