What does autoload do in zsh?

41.7k Views Asked by At

I wasn't able to find a documentation for the widely used autoload command in zsh. Does anybody can explain it in plain English?

A bit more specific: What does autoloading of modules mean, for example in this line:

autoload -Uz vcs_info

What does it do?


I've tried autoload --help, man autoload, googling - no success. Thanks!

2

There are 2 best solutions below

11
On BEST ANSWER

The autoload feature is not available in bash, but it is in ksh (korn shell) and zsh. On zsh see man zshbuiltins.

Functions are called in the same way as any other command. There can be a name conflict between a program and a function. What autoload does is to mark that name as being a function rather than an external program. The function has to be in a file on its own, with the filename the same as the function name.

autoload -Uz vcs_info

The -U means mark the function vcs_info for autoloading and suppress alias expansion. The -z means use zsh (rather than ksh) style. See also the functions command.

Edit (from comment, as suggested by @ijoseph):

So it records the fact that the name is a function and not an external program - it does not call it unless the -X option is used, it just affects the search path when it is called. If the function name does not collide with the name of a program then it is not required. Prefix your functions with something like f_ and you will probably never need it.

For more detail see http://zsh.sourceforge.net/Doc/Release/Functions.html.

1
On

autoload tells zsh to look for a file in $FPATH/$fpath containing a function definition, instead of a file in $PATH/$path containing an executable script or binary.

Script

A script is just a sequence of commands that get executed when the script is run. For example, suppose you have a file called hello like this:

echo "Setting 'greeting'"
greeting='Hello'

If the file is executable and located in one of the directories in your $PATH, then you can run it as a script by just typing its name. But scripts get their own copy of the shell process, so anything they do can't affect the calling shell environment. The assignment to greeting above will be in effect only within the script; once the script exits, it won't have had any impact on your interactive shell session:

$ hello
Setting 'greeting'
$ echo $greeting

$ 

Function

A function is instead defined once and stays in the shell's memory; when you call it, it executes inside the current shell, and can therefore have side effects:

hello() {
  echo "Setting 'greeting'"
  greeting='Hello'
}

$ hello
Setting 'greeting'
$ echo $greeting
Hello

So you use functions when you want to modify your shell environment. The Zsh Line Editor (ZLE) also uses functions - when you bind a key to some action, that action is defined as a shell function (which has to be added to ZLE with the zle -N command).

If you have a lot of functions, then you might not want to define all of them in your .zshrc every time you start a new shell; that slows down shell startup and uses memory to store functions that you might not wind up calling during the lifetime of that shell. So you can instead put the function definitions into their own files, named after the functions they define, put those files into a directory ( I use $HOME/lib/ksh/functions myself), and include the directory in the environment variable $FPATH – which, like $PATH, is a colon-separated list of directories. (Also like PATH, it's tied to a lowercase equivalent $fpath, which presents the same list of directories as an array instead of a single string.)

Zsh comes with a number of standard functions in its install tree, in a set of directories already included in the default value of $FPATH. But FPATH and the files in its directories are not part of zsh's normal command lookup; they're ignored unless you have first specified that a certain command is the name of a function whose definition can be found by way of FPATH.

That's what autoload does: it says "Hey, Zsh, this command name here is a function, so when I try to run it, go look for its definition in my FPATH, instead of looking for an executable in my PATH."

The first time you run a command which Zsh determines is an autoloaded function, the shell sources the definition file. Then, if there's nothing in the file except the function definition, or if the shell option KSH_AUTOLOAD is set, it proceeds to call the function immediately with the arguments you supplied. But if that option is not set and the file contains any code outside the function definition (such as initialization of variables used by the function), the function is not called automatically. In that case it's up to you to call the function inside the file after defining it, so that first invocation will still happen.

I have my .zshrc autoload all the files in my personal functions directory (not the whole fpath); that takes up much less memory and time than actually loading all of their definitions on startup, while still keeping them available at my prompt without any additional setup. Here is the relevant bit of my zshrc; I put the code into an anonymous function just to avoid adding an extraneous variable to my shell:

() {
    # add our local functions dir to the fpath
    local funcs=$HOME/lib/zsh/functions

    # FPATH is already tied to fpath, but this adds
    # a uniqueness constraint to prevent duplicate entries
    typeset -TUg +x FPATH=$funcs:$FPATH fpath
    
    # Now autoload them
    if [[ -d $funcs ]]; then
        autoload ${=$(cd "$funcs" && echo *)}
    fi
}

That last autoload line is not super robust; it assumes that none of my function file names has funny characters, and that there aren't too many of them to fit on a single command line. But under those constraints it works fine, and is a bit more efficient than a loop.