在 zsh 中定位函数的源代码

在 zsh 中定位函数的源代码

我的 zsh shell 中有一个烦人的问题,在某个地方声明了一个函数,该函数名为“cp”,因此它覆盖了正常的 cp 行为。我试图找到函数声明,但找不到。我已经查看了 .zshrc 的正常位置以及 .zshrc 中包含的各种其他源,但到目前为止一无所获。

我还尝试过其他方法:

  • grep -r 'function cp' .(出自~)
  • whence -f cp(给出了函数定义但没有给出它的声明位置)

有任何想法吗?

答案1

首先,可以定义一个没有function关键字的函数,因此更好的搜索是

grep 'cp()' .*

这将搜索诸如.zshrc.profile之类的文件。如果没有找到任何内容,您可能还想查看 加载的各种文件zsh。这些文件列在 的最末尾man zsh

FILES
       $ZDOTDIR/.zshenv
       $ZDOTDIR/.zprofile
       $ZDOTDIR/.zshrc
       $ZDOTDIR/.zlogin
       $ZDOTDIR/.zlogout
       ${TMPPREFIX}*   (default is /tmp/zsh*)
       /etc/zsh/zshenv
       /etc/zsh/zprofile
       /etc/zsh/zshrc
       /etc/zsh/zlogin
       /etc/zsh/zlogout    (installation-specific - /etc is the default)

默认情况下$ZDOTDIR应该是你的$HOME。因此,此命令应该可以找到有问题的文件:

grep 'cp()\|cp ()' ~/.zshenv ~/.zprofile ~/.zshrc ~/.zlogin /etc/zsh/zshenv \
 /etc/zsh/zprofile /etc/zsh/zshrc /etc/zsh/zlogin 

我添加了,\|因为函数名称和函数本身之间也可以有空格。最后,@Dennis 指出如果使用关键字,也可以省略括号function。因此,为了更加安全,请执行以下操作:

grep -E 'function cp|cp *\(\)' ~/.zshenv ~/.zprofile ~/.zshrc ~/.zlogin \
  /etc/zsh/zshenv /etc/zsh/zprofile /etc/zsh/zshrc /etc/zsh/zlogin 

答案2

我今天需要这样做,发现whence -v输出包含函数定义的文件。

$ whence -v function_name
function_name is a shell function from /path/to/file

答案3

较新版本的 zsh(自 5.4 版起,在提交中添加34f70c5)支持$functions_source数组作为zsh/parameter模块的一部分(文档:)man zshmodules

functions_source

这个只读关联数组将启用的函数名称映射到包含该函数源的文件的名称。

对于已经加载的自动加载函数,或使用绝对路径标记为自动加载的自动加载函数,或已使用“ functions -r”解析其路径的自动加载函数,这是找到的用于自动加载的文件,并解析为绝对路径。

对于在脚本或源文件主体内定义的函数,这是该文件的名称。在这种情况下,这是该文件最初使用的准确路径,可能是相对路径。

对于任何其他函数(包括在交互提示下定义的函数或路径尚未解析的自动加载函数),此为空字符串。但是,只要函数存在,哈希元素就会被报告为已定义:此哈希的键与 的键相同$functions

所以你可以这样做

echo $functions_source[cp]

答案4

Terdon 的回答已经给了你适当的grep命令来捕获函数定义的所有可能的变体。

我想再补充两点。

  1. 获取文件列表,实际上读入(例如非标准文件可能由另一个文件获取!),您可以启用zshSOURCE_TRACE选项来调用:

    $ zsh -o sourcetrace
    +/etc/zshenv:1> <sourcetrace>
    +/home/user/.zshrc:1> <sourcetrace>
    +/home/user/.zcompdump:1> <sourcetrace>
    +/home/user/.zshrc-last:1> <sourcetrace>
    
  2. 使用这种“grep 方法”,你将无法捕获以下函数自动加载通过autoload内置。因此,也请检查一下您的fpath

    $ for i ($fpath) { ls -l "$i"/cp }
    

相关内容