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

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

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

compose() {
  docker-compose $*
}

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

rails() {
  run "rails $*"
}

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

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

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

我的 zsh 版本:

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

答案1

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

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

如果我定义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请注意、--rm、等如何app作为单独的参数在 中传递,bash以及如何作为单个参数传递zsh

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

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

compose() { docker-compose "$@"; }
run() { compose run --rm app "$@"; }
rails() { run rails "$@"; }

相关内容