I have come across *.zwc files, which I believe are Z-shell Word Code files, or compiled zsh script.

When source-ing an arbitrary file, is there a way to have zsh:

  • Use the file's .zwc if it exists and is newer than the file
  • Else, compile the file to Z-shell Word Code and then source it

If I have a file containing only functions, is the answer any different?

There don't seem to be many tutorials around Z-shell Word Code, so feel free to point me at them.


At least in order to use .zwc files, you do not have to do anything. As the section on the . command in the Zsh's manpage states:

[…] If a file named ‘file.zwc’ is found, is newer than file, and is the compiled form (created with the zcompile builtin) of file, then commands are read from that file instead of file.

The same is true for source, as it is the same as ., except for the search order.

Automatically compiling any sourced scripts could be done by creating wrapper functions. For example:

source () {
    [[ ! "$1.zwc" -nt $1 ]] || zcompile $1
    builtin source $@

. () {
    [[ ! "$1.zwc" -nt $1 ]] || zcompile $1
    builtin . $@

Of course as these wrappers are very simple and might need some extra fail-saves. For example if the directory, in which the file to be sourced resides, is not writable. Also, the compilation might fail, even if the the source file has no syntax errors.

| improve this answer | |

Based on Adaephon's answer, I wrote a complete drop-in replacement of both source and ..

It wasn't easy because of the builtin behaviour of passing $@ if no arguments are given.

The required aliases are in the comments.


# This file needs to be `sourced` to ensure a drop-in behaviour for `source` or `.`
# The shell passess "$@" to source if no arguments are given after the file to be sourced.

# Works in bash.

# Required aliases are:
# alias source='builtin source compile-source-file source "$#" "$@"'
# alias      .='builtin .      compile-source-file .      "$#" "$@"'

# zsh: compile functions before sourcing
# This function expects to be called with:
# $1 builtin to use, either `.` or `source`.
# $2 file to source
# $3... arguments to pass to sourced file
function compile_then_source () {
  local method=$1 file=$2; shift 2; local args=("$@")

  # ${var@Q} gives value of var quoted in a format that can be reused as input
  [[ $BASH_VERSION ]] && { eval builtin "$method" "$file" "${args@Q}"; return $?; }

  if [[ ! $file.zwc -nt $file ]]; then
    # Use canonical pathname for zrecompile's happiness
    if [[ -r $file && -w ${file:h} ]]; then zcompile "${file:P}"; fi

  eval builtin "$method" "$file" "${(q)args[@]}"

function main () {
  local use_builtin=$1  # '.' or 'source'
  local num_args=$2     # Number of elements in calling shell's $@, which follow
  shift 2;
  local wrapper_args=("$@")
  shift "$num_args"
  local file=$1; shift;

  # Now $@ is the arguments passed after the file to be soured
  if [[ $# -ge 1 ]]; then # arguments were passed
  else  # use $@ from the wrapper args
  compile_then_source "$use_builtin" "$file" "${use_args[@]}"

main "$@"

unset -f main compile_then_source
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.