为什么 zsh 在这些函数中用下划线替换连字符?

Nat*_*han 0 zsh function

我在 zsh 和 bash 控制台中获得了以下函数别名:

compose() {
  docker-compose $*
}

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

rails() {
  run "rails $*"
}
Run Code Online (Sandbox Code Playgroud)

在 bash 中,运行rails c通过 docker-compose 成功启动了 Ruby on Rails 控制台。

在 zsh 中,运行会rails c导致命令未找到错误,其中连字符被下划线替换:

? rails c
No such command: run __rm app rails c
Run Code Online (Sandbox Code Playgroud)

我的 zsh 版本:

? zsh --version
zsh 5.6.2 (x86_64-apple-darwin18.0.0)
Run Code Online (Sandbox Code Playgroud)

mos*_*svy 5

这不是zsh用下划线替换破折号,而是可能是那个docker-compose程序,或者它调用的另一个程序。

问题是zsh,与 不同bashIFS默认情况下不会拆分未加引号的变量。

如果我将其定义docker-compose为一个函数,该函数打印由 包围的每个参数{},这就是我获得的:

$ 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}
Run Code Online (Sandbox Code Playgroud)

请注意如何run--rmapp,等作为单独的参数传递bash,并作为一个参数zsh

那是因为bash确实$*使用空格( 的默认值IFS)作为分隔符将变量拆分并修剪为多个参数。可以zsh通过使用$=*代替$*set -o SH_WORD_SPLIT选项来获得相同的效果,但这将使脚本仅使用 zsh。

你应该使用"$@"而不是$*无处不在,除非你有一些非常特殊的理由不这样做:

compose() { docker-compose "$@"; }
run() { compose run --rm app "$@"; }
rails() { run rails "$@"; }
Run Code Online (Sandbox Code Playgroud)