18

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?

4 Answers 4

5

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 
4
  • 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
    Jan 26, 2014 at 22:16
  • @Dennis I stand corrected, I was thinking of globbing which is completely irrelevant here. Thanks, answer corrected.
    – terdon
    Jan 26, 2014 at 22:19
  • Also, the parentheses are optional if the function keyword is used. grep -E 'function cp|cp *\(\)' should catch all cases.
    – Dennis
    Jan 26, 2014 at 22:24
  • @Dennis fair enough, thanks again, answer edited.
    – terdon
    Jan 26, 2014 at 22:26
53

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
3
  • Can you post your version of zsh? I don't see output like that with zsh 5.0.2
    – Tarrasch
    Jul 20, 2016 at 10:11
  • 1
    Worked for me with zsh 5.3
    – minseong
    Nov 23, 2017 at 16:30
  • Works for me with 5.1.1. I also want to add that, though it looks like another response was flagged as the answer, I'd recommend this one first. It's a quick, clean solution that uses built in functionality to do precisely what was asked for.
    – Jon Carter
    Sep 7, 2020 at 4:19
8

Newer versions of zsh (since 5.4, added in commit 34f70c5) support 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 $functions.

So, you can do

echo $functions_source[cp]
2

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 }
    

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .