$ freebsd-version
10.3-RELEASE-p17
$
portinstall() {
port="$1"; shift
env="$@"
#1
env "$@" printenv | grep -E '^WITH(OUT)?='
#2
env "$env" printenv | grep -E '^WITH(OUT)?='
#3
env "$*" printenv | grep -E '^WITH(OUT)?='
#4
env $@ printenv | grep -E '^WITH(OUT)?='
#5
env $* printenv | grep -E '^WITH(OUT)?='
}
portinstall foo/bar WITH='baz xyzzy' WITHOUT='quux'
只有#1有效,其输出:
WITHOUT=quux
WITH=baz xyzzy
#2,#3(WITH只是一个变量" baz xyzzy WITHOUT = quux"):
WITH=baz xyzzy WITHOUT=quux
#4,#5
env: xyzzy: No such file or directory
我的主要问题是为什么#1有效,但看似等同的#2没有?
答案 0 :(得分:2)
使用"$@"
通常是正确的,但也许这种分析可以帮助您理解原因。
您的代码大约是:
env="$@"
#1
env "$@" printenv | grep -E '^WITH(OUT)?='
#2
env "$env" printenv | grep -E '^WITH(OUT)?='
#3
env "$*" printenv | grep -E '^WITH(OUT)?='
#4
env $@ printenv | grep -E '^WITH(OUT)?='
#5
env $* printenv | grep -E '^WITH(OUT)?='
并且您正在使用参数WITH='baz xyzzy' WITHOUT='quux'
调用脚本。是的,你有一个功能和一个备用的参数$1
增加了复杂性,但它们大多不相关;这是核心。
通常,$*
映射到由空格分隔的参数中的单词; $@
也是如此。当用双引号括起来时,它们的行为不同:"$@"
扩展为保留内部空格的参数集,而"$*"
映射到保留内部空间且参数之间有单个空格的单个字符串。
但是,在env="$@"
的上下文中,赋值行为类似于env="$*"
- 您最终会在变量中使用单个字符串。为了保留单独的参数,在Bash中,您使用数组:
env=("$@")
您可以使用以下方式打印它们:
printf '%s\n' "${env[@]}"
但是,它正在切断。
使用#1,您最后调用env
两个有效的空间保留分配,printenv
正式打印和grep
过滤器,为您提供两个变量值。这就是"$@"
通常正确的原因。
使用#2和#3,最终调用env
,其中一个字符串以WITH=
开头(因此它分配给变量WITH
,其余部分为字符串是baz xyzzy WITHOUT=quux
,这就是为什么你看到它作为输出。有一个单一的环境变量 - WITH - 但它的值包含空格和赋值。
#4和#5,你已经跑了:
env WITH=baz xyzzy WITHOUT=quux printenv
由于xyzzy
不是赋值,因此它被视为要使用参数WITHOUT=quux
和printenv
(以及WITH=baz
添加到环境中)调用的命令,但是你的PATH上没有名为xyzzy
的程序,因此env
会给你错误。您可以创建一个程序xyzzy
来显示正在发生的事情。
使用数组env
,您可以运行:
env "${env[@]}" printenv | …
你得到与#1相同的结果。