Есть много функций, которые можно использовать в оболочке Bash. Их определения могут быть перечислены в set
, но как найти, в каких файлах определены определенные пользовательские функции?
Включите отладку. Из руководства по Bash :
extdebug
Если установлено при вызове оболочки или в файле запуска оболочки, организуйте выполнение профиля отладчика до запуска оболочки идентично опции
--debugger
. Если установлено после вызова, поведение, предназначенное для использования отладчиками, включено:blockquote>
- Опция
-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()
Обычно читает точечный файл для каждого пользователя 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}
$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(){