This blog has been archived.
Visit my home page at zhimingwang.org.

Zsh: save stdout, stderr, and return value of command to different variables (without temp file)

This is something worth sharing. The idea was based on this SO answer, and I cooked up this particular implementation to remove potential race conditions, with input from Mathias Fredriksson1. See mafredri/zsh-async#1, and in particular this comment for explanation.

# The following construct evaluates "$@" and saves output on stdout in the
# parameter stdout, output on stderr in the parameter stderr, and return value
# in the parameter return.
#
# The idea was based on http://stackoverflow.com/a/18086548/1944784, but this
# implementation is completely race-condition-free. The implementation was
# refined during my exchange with Mathias Fredriksson @mafredri, in
# https://github.com/mafredri/zsh-async/issues/1. See mainly
# https://github.com/mafredri/zsh-async/issues/1#issuecomment-121468958, where
# the advantage of this implementation is explained.

unset stdout stderr ret
eval "
$(
    {
        stdout=$(eval "$@")
        ret=$?
        typeset -p stdout ret
    } 2> >(stderr=$(cat); typeset -p stderr)
)"

Also available as a gist.


  1. Mathias (@mafredri) is the author of the lovely zsh-async library, and a maintainer of sindresorhus/pure. He forever revolutionalized my prompt.↩︎