what is the zsh equivalent of bash's export -f

Environment variables containing functions are a bash hack. Zsh doesn't have anything similar. You can do something similar with a few lines of code. Environment variables contain strings; older versions of bash, before Shellshock was discovered, stored the function's code in a variable whose name is that of the function and whose value is () { followed by the function's code followed by }. You can use the following code to import variables with this encoding, and attempt to run them with bash-like settings. Note that zsh cannot emulate all bash features, all you can do is get a bit closer (e.g. to make $foo split the value and expand wildcards, and make arrays 0-based).

bash_function_preamble='
    emulate -LR ksh
'
for name in ${(k)parameters}; do
  [[ "-$parameters[name]-" = *-export-* ]] || continue
  [[ ${(P)name} = '() {'*'}' ]] || continue
  ((! $+builtins[$name])) || continue
  functions[$name]=$bash_function_preamble${${${(P)name}#"() {"}%"}"}
done

(As Stéphane Chazelas, the original discoverer of Shellshock, noted, an earlier version of this answer could execute arbitrary code at this point if the function definition was malformed. This version doesn't, but of course as soon as you execute any command, it could be a function imported from the environment.)

Post-Shellshock versions of bash encode functions in the environment using invalid variable names (e.g. BASH_FUNC_myfunc%%). This makes them harder to parse reliably as zsh doesn't provide an interface to extract such variable names from the environment.

I don't recommend doing this. Relying on exported functions in scripts is a bad idea: it creates an invisible dependency in your script. If you ever run your script in an environment that doesn't have your function (on another machine, in a cron job, after changing your shell initialization files, …), your script won't work anymore. Instead, store all your functions in one or more separate files (something like ~/lib/shell/foo.sh) and start your scripts by importing the functions that it uses (. ~/lib/shell/foo.sh). This way, if you modify foo.sh, you can easily search which scripts are relying on it. If you copy a script, you can easily find out which auxiliary files it needs.

Zsh (and ksh before it) makes this more convenient by providing a way to automatically load functions in scripts where they are used. The constraint is that you can only put one function per file. Declare the function as autoloaded, and put the function definition in a file whose name is the name of the function. Put this file in a directory listed in $fpath (which you may configure through the FPATH environment variable). In your script, declare autoloaded functions with autoload -U foo.

Furthermore zsh can compile scripts, to save parsing time. Call zcompile to compile a script. This creates a file with the .zwc extension. If this file is present then autoload will load the compiled file instead of the source code. You can use the zrecompile function to (re)compile all the function definitions in a directory.


If you put your function declaration in .zshenv, your function will be usable from a script without any effort.