I have a build script that can change what binaries are in my $PATH (it doesn't edit $PATH itself, but it adds/deletes files to folders that are already in $PATH). zsh's autocompletion doesn't update to reflect the files that have been added/deleted in response to the build, so I have to either restart the shell or execute the 'rehash' shell built-in to tell it to update its autocomplete cache.

I decided I wanted to automate running rehash so at first I did this:

build() {
    ~/bin/real_build && rehash

But shell functions run in their own subshell, so rehash would update the cache for the subshell, instead of the shell in the terminal I was using. So I switched to this:

alias build='~/bin/real_build && rehash'

Which works, except when I want to pass arguments to build. If I pass 'clean' I'd like it to execute:

~/bin/real_build clean && rehash

But instead it will do:

~/bin/real_build && rehash clean

So I'm stuck -- I can use an alias and not be able to pass arguments, or I can use a function and not have it actually update the autocomplete entries. Is there a way to make both work?

  • I may be wrong because I've never used zsh before today, but calling rehash from a function does seem to work for me.
    – lk-
    Aug 17, 2012 at 15:58

3 Answers 3


Shell functions do not run in their own subshell, unless you use parentheses instead of the usual curly brackets around the body. Your function does update the executable hash on every version of zsh that I've seen, and I don't think there's an option to change this behavior.


I think source might be the best option here. Here is an example:

cat << EOF > foo
touch $1
chmod +x $1

Execute foo like this:

source foo bar

If this was in your path, bar is now completable.


A shell function gets params just like a shell script. "$@", $* $1... $n. All other ops work, too.

Try using a parameter to the function, in this case $1.

build() {
    ~/bin/real_build ${1} && rehash

Do not use quotes unless your real_build script can handle "" as a parameter.
"" is different from nothing.

It's a good way to create an "alias" that needs args in specific places.

  • Would make more sense to use ~/bin/real_build "$@" && rehash here to pass all the parameters. If you wanted to pass up to 1 of the parameters, that would rather be "$@[0,1]". With $1, you end up passing 0 argument to real_build in both build and build "". Jan 22, 2021 at 14:48

You must log in to answer this question.

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