Locating the source of a function in zsh

7

2

I have this annoying issue in my zsh shell where a function is being declared somewhere and that function is named "cp" so it's overriding the normal cp behavior. I'm trying to locate the function declaration but I can't. I already looked in the normal places of .zshrc and the various other sources that are being included in .zshrc but so far nothing.

Other things I've tried:

  • grep -r 'function cp' . (from ~)
  • whence -f cp (gives the function definition but not where it's declared from)

Any ideas?

asolberg

Posted 2014-01-26T21:26:18.633

Reputation: 263

Answers

4

First of all, a function can be defined without the function keyword so a better search would be

grep 'cp()' .*

That will search through files such as .zshrc and .profile and whatnot. If that finds nothing, you might also want to see the various files loaded by zsh. These are listed at the very end of 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)

By default $ZDOTDIR should be your $HOME. So, this command should find your offending file:

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

I added the \| since you can also have spaces between the function name and the function itself. Finally, @Dennis points out that the parentheses can also be omitted if you use the function keyword. So, to be even more safe, do this:

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

terdon

Posted 2014-01-26T21:26:18.633

Reputation: 45 216

grep will not search for files beginning with a . so it is pretty much useless. That's not true. When used with the -r switch, grep will go trough all files in directories it encounters. (At least my version of grep does.) – Dennis – 2014-01-26T22:16:13.047

@Dennis I stand corrected, I was thinking of globbing which is completely irrelevant here. Thanks, answer corrected. – terdon – 2014-01-26T22:19:11.803

Also, the parentheses are optional if the function keyword is used. grep -E 'function cp|cp *\(\)' should catch all cases. – Dennis – 2014-01-26T22:24:58.690

@Dennis fair enough, thanks again, answer edited. – terdon – 2014-01-26T22:26:19.007

15

I needed to do this today and found that whence -v outputs the file containing the function definition.

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

Will Adams

Posted 2014-01-26T21:26:18.633

Reputation: 151

Can you post your version of zsh? I don't see output like that with zsh 5.0.2 – Tarrasch – 2016-07-20T10:11:40.407

1Worked for me with zsh 5.3 – theonlygusti – 2017-11-23T16:30:28.557

2

Newer versions of zsh (since 5.4, added in commit 34f70c5) supports the $functions_source array as part of the zsh/parameter module (documentation: man zshmodules):

functions_source

This readonly associative array maps names of enabled functions to the name of the file containing the source of the function.

For an autoloaded function that has already been loaded, or marked for autoload with an absolute path, or that has had its path resolved with ‘functions -r’, this is the file found for autoloading, resolved to an absolute path.

For a function defined within the body of a script or sourced file, this is the name of that file. In this case, this is the exact path originally used to that file, which may be a relative path.

For any other function, including any defined at an interactive prompt or an autoload function whose path has not yet been resolved, this is the empty string. However, the hash element is reported as defined just so long as the function is present: the keys to this hash are the same as those to $funcions.

So, you can do

echo $functions_source[cp]

univerio

Posted 2014-01-26T21:26:18.633

Reputation: 121

0

Terdon's answer already gave you the appropriate grep command to catch all possible variants of a function definition.

I want to add two more points.

  1. To get a list of files, which are actually read in (e.g. a non-standard file might be sourced by another file!), you can invoke zsh with the SOURCE_TRACE option enabled:

    $ zsh -o sourcetrace
    +/etc/zshenv:1> <sourcetrace>
    +/home/user/.zshrc:1> <sourcetrace>
    +/home/user/.zcompdump:1> <sourcetrace>
    +/home/user/.zshrc-last:1> <sourcetrace>
    
  2. With this ,,grep-approach'' you won't catch functions which are autoloaded via the autoload builtin. So, do a check of your fpath, too:

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

mpy

Posted 2014-01-26T21:26:18.633

Reputation: 20 866