Answers:
打开调试。从Bash手册:
extdebug
如果是在shell调用或在shell启动文件中设置的,则与shell
--debugger
选项相同,安排在shell启动之前执行调试程序配置文件 。如果在调用后设置,则启用了供调试器使用的行为:
- 该
-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
。
find_function()( shopt -s extdebug; declare -F "$@"; )
。使用函数体上的括号,它会在子shell中执行,并且对shopts的更改不会影响调用方。而且-f
似乎不需要。
实际上,这比起初看起来要复杂得多。Shell读取哪些文件取决于当前正在运行的Shell类型。无论是交互式还是非交互式,是登录外壳程序还是非登录外壳程序,以及上述各项的组合。要搜索所有可由不同的Shell读取的默认文件,可以执行以下操作(更改$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(){
+=
array+="foo"
将字符串附加foo
到数组的第一个元素上?
在通常的每用户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}