如何查找定义了bash函数的文件?


33

我无法弄清楚如何找到定义了bash函数的文件(__git_ps1在我的情况下)。

我尝试了declaretypewhich,但没有告诉我的源文件。我读到declare可以打印文件名和行号的地方,但是没有说明如何打印。的help页面declare也不说。

我如何获得此信息?


如果函数文件的路径未包含在中$PATHtype则将无法使用。您可能只想尝试使用findlocatelocate它将更快,因为它使用了预先存在的数据库,但是如果该命令是最近才安装的,它将无法工作。
user628544 '16

Answers:


37

如果准备运行该函数,则可以通过set -x跟踪执行和设置PS4变量来获取信息。

  1. 从bash开始,--debuggershopt -s extdebug用于记录额外的调试信息。

  2. 设置PS4,在跟踪时显示“提示”以显示源代码行。

  3. 打开跟踪。

  4. 然后,您可以运行函数,并且对于每一行,您将获得函数的文件名。

  5. 用于set +x关闭跟踪。

因此,在这种情况下,您可以运行

bash --debugger
PS4='+ ${BASH_SOURCE[0]} '
set -x ; __git_ps1 ; set +x

“ -x在扩展了每个简单命令(对于命令,大小写命令,选择命令或对命令的算术之后)后,显示PS4的扩展值,然后显示该命令及其扩展的参数或关联的单词列表。” 真好!
l0b0

25

如果您不愿意运行该功能,则仍然可以设置调试并获取信息。步骤是

  1. 开始bash --debuggershopt -s extdebug在定义函数之前。
  2. declare -F __git_ps1

并将报告该函数的定义位置。

与使用PS4查看带注释的执行跟踪相比,此方法的优点是

  • 输出少很多
  • 它直接回答了这个问题

执行跟踪的优点是

  • 一次查看所有调用的函数
  • 查看被调用函数之间的关系
  • 查看递归

强烈建议shopt -s extdebug同时使用两者,~/.bashrc~/.bash_profile介绍不同调用情况下使用的不同文件


1
如果定义函数shopt -s extdebug调用它也将起作用。如果通过声明函数,请注意行号可能会关闭(当前错误)eval
斯特凡Chazelas

我对vpnc的误导是在完成之后。在bash --debugger我必须实际触发完成操作以获取定义的完成功能并从中获取报告之后declare -F _vpnc
哈拉尔德

9

@icarus的出色解决方案适用于函数,只要它们是按字面定义的,而不是eval另一个文件的内容(其中带有的文件eval将作为源显示)结果的结果。它不会打印别名,shell内置文件(如echo)和可执行文件(是否为二进制文件)的源文件,并且我相信通常不会提供此信息。在正常执行过程中或响应信号时,某些命令可能会打印其源文件(甚至可能是真实的)。

__git_ps1是在我的系统Arch Linux 中/usr/share/git/git-prompt.sh及其/usr/share/git/completion/git-prompt.sh上定义的,因此对您来说可能是相同的。

看一下“ 调用”部分man bash是否需要查找专门在Shell开头提供的命令-它们可能会获取其他文件,而这些文件又会获取其他文件。


可以获取启动时来源的文件列表bash吗?
pfnuesel

@pfnuesel-由您决定。默认值为in $HOME/.bashrc和in $HOME/.profile。请参阅:linuxfromscratch.org/blfs/view/svn/postlfs/profile.html,其中解释了何时以及如何获取每个文件的一些详细信息。

2
@Joe gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html是一个更好的参考。/etc/profile$HOME/.bash_profile$HOME/.bash_login,和的内容$ENV$BASH_ENV需要被添加到列表中。
icarus

@icarus-谢谢。这是一个更好的解释。

8

在中似乎没有可能bash,但是在中zsh

$ type __git_ps1
> __git_ps1 is a shell function from /usr/share/git/git-prompt.sh

这个问题确实说明了bash ...
Jeff Schaller

4
@JeffSchaller:使用此答案的明显方法是设置zsh来获取与bash相同的文件,然后使用它来查找定义。这个答案是不建议切换到zsh的,只是它显然能够理解shell语法比一般的工具,如一个有用的工具find/ locate/ grep
彼得·科德斯

那么,我会说@PeterCordes,这个答案目前不符合您所说的回答问题的目的。我不知道zsh是否原生读取与bash相同的文件。
Jeff Schaller

@JeffSchaller:同意这个答案需要改进。~/.whatever缺省情况下,zsh几乎可以肯定不会读取与bash 相同的文件,并且只会对共享位置中定义的函数(例如在这种情况下,未在其中重新定义)提供有用的答案~/.bashrc
彼得·科德斯

-1

声明一个具有相同名称的函数,并尽早将其设置为只读,然后激活xtrace模式,例如:

__git_ps1(){ :;}
readonly -f __git_ps1
set -x

之后,当您登录时,将看到包括文件源的跟踪信息。在尝试声明现有只读函数的瞬间,您将看到一条错误消息。之前的最后一个源文件应包含您要查找的声明。

您可能需要将其放入系统bash配置文件中。还请记住在找到罪魁祸首后还原更改。


-3

你有尝试过吗?

grep -rnw '/path/to/somewhere/' -e "pattern" 

或此处找到的任何其他命令:

如何在Linux上找到所有包含特定文本的文件?| 堆栈溢出

看来我需要给您更多的解释。您的问题询问“”,因此,如果运行以下命令,它将返回定义了bash函数的所有文件。

grep -rnw 'Path2Search' -e "#!/bin/bash"

BASH编程-函数| Linux文档项目


1
绝对不鼓励仅链接的答案。请添加一些说明。
heemayl
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.