1

I've got the following function aliases sourced in zsh and bash consoles:

compose() {
  docker-compose $*
}

run() {
  compose "run --rm app $*"
}

rails() {
  run "rails $*"
}

In bash, running rails c starts a Ruby on Rails console through docker-compose successfully.

In zsh, running rails c results in a command not found error where the hyphens are replaced by underscores:

➜ rails c
No such command: run __rm app rails c

My zsh version:

➜ zsh --version
zsh 5.6.2 (x86_64-apple-darwin18.0.0)

1 Answer 1

6

It's not zsh that's replacing dashes with underscores, but probably that docker-compose program, or another program called by it.

The problem is that zsh, unlike bash, does not split unquoted variables with IFS by default.

If I define docker-compose as a function that prints each of its argument surrounded by {}, this is what I obtain:

$ cat example
docker-compose() {
        echo -n docker-compose
        for f in "$@"; do echo -n " {$f}"; done; echo
}
compose() { docker-compose $*; }
run() { compose "run --rm app $*"; }
rails() { run "rails $*"; }   
rails c

$ zsh example
docker-compose {run --rm app rails c}

$ bash example
docker-compose {run} {--rm} {app} {rails} {c}

Notice how run, --rm, app, etc. are passed as separate arguments in bash and as a single argument in zsh.

That's because bash did split and trim the $* variable into multiple arguments using spaces (the default value of IFS) as the delimiter. The same effect could be obtained in zsh by using $=* instead of $*, or by the set -o SH_WORD_SPLIT option, but that will make the script zsh-only.

You should use "$@" instead of $* everywhere, unless you have some very special reason not to:

compose() { docker-compose "$@"; }
run() { compose run --rm app "$@"; }
rails() { run rails "$@"; }
3
  • Thanks for the great example script! I'm confused if you are recommending using $=* or "$@". I had already tried the latter though and it didn't seem to make a difference. I'll try $=*.
    – Nathan
    Commented Oct 22, 2018 at 17:33
  • 1
    I do not recommend using $=* or other zsh-specific features. I've only added it for completeness' sake. The example at the end of my answer uses "$@" and works the same in any shell, and the same as your example in bash. Notice that the quotes in run() and rails() are only around "$@".
    – user313992
    Commented Oct 22, 2018 at 17:52
  • Moving the quotes around only the "$@" did the trick! Thanks.
    – Nathan
    Commented Oct 22, 2018 at 19:09

You must log in to answer this question.

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