Как я могу найти, где определена определенная функция bash?

Есть много функций, которые можно использовать в оболочке Bash. Их определения могут быть перечислены в set, но как найти, в каких файлах определены определенные пользовательские функции?

28
задан 26 May 2019 в 12:23

3 ответа

Включите отладку. Из руководства по Bash :

extdebug

Если установлено при вызове оболочки или в файле запуска оболочки, организуйте выполнение профиля отладчика до запуска оболочки идентично опции --debugger. Если установлено после вызова, поведение, предназначенное для использования отладчиками, включено:

  • Опция -F встроенной функции declare (см. Встроенные команды Bash ) отображает имя исходного файла и номер строки, соответствующий каждому имени функции, указанному в качестве аргумента.

Пример:

$ 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()
0
ответ дан 26 May 2019 в 12:23

Обычно читает точечный файл для каждого пользователя 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}
0
ответ дан 26 May 2019 в 12:23
1139 Это на самом деле сложнее, чем кажется на первый взгляд. Какие файлы читаются вашей оболочкой, зависит от того , какой тип оболочки вы используете в данный момент. Является ли это интерактивным или нет, будь то оболочка для входа в систему или не для входа в систему и какая комбинация вышеперечисленного. Для поиска по всем файлам по умолчанию, которые могут быть прочитаны различными оболочками, вы можете сделать (замените $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 включает Perl-совместимые регулярные выражения (PCRE), которые позволяют нам использовать более интересный синтаксис регулярных выражений. В частности:

  • (^|\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

Как вы можете видеть, однако, это напечатает всю совпавшую строку. Что нас действительно интересует, так это список имен файлов, а не строка, которая их вызывает. Вы можете получить те с этим, более сложным, регулярным выражением:

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 означает «печатать только соответствующую часть строки». Дополнительные элементы, добавленные в регулярное выражение:

  • \K: игнорировать все, что соответствовало этой точке. Это трюк PCRE, который позволяет вам использовать сложное регулярное выражение для поиска соответствия, но не включать эту совпадающую часть при использовании флага 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

Обратите внимание, что я использовал ., за которым следует пробел, который не используется для поиска источников, но это потому, что у меня есть псевдоним, который вызывает другой язык, а не bash. Это то, что дает странные $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(){
0
ответ дан 26 May 2019 в 12:23

Другие вопросы по тегам:

Похожие вопросы: