Ответы:
Включите отладку. Из руководства 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()
shopt -s extdebug; declare -Ff quote; shopt -u extdebug
.
find_function()( shopt -s extdebug; declare -F "$@"; )
. С паренами в теле функции, он выполняется в подоболочке, и изменение в shopts не влияет на вызывающего. И -f
, кажется, не нужно.
Это на самом деле сложнее, чем кажется на первый взгляд. Какие файлы читаются вашей оболочкой, зависит от того, какую оболочку вы используете в данный момент. Является ли это интерактивным или нет, будь то оболочка для входа в систему или не для входа в систему и какая комбинация вышеперечисленного. Чтобы выполнить поиск по всем файлам по умолчанию, которые могут быть прочитаны различными оболочками, вы можете сделать это (изменить $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 Compatible Regular Expressions (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, который позволяет вам использовать сложное регулярное выражение для поиска соответствия, но не включать эту совпадающую часть при использовании -o
флага grep .В моей системе приведенная выше команда вернет:
$ 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(){
+=
array+="foo"
добавления строки foo
к 1-му элементу массива?
Обычные для каждого пользователя 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}