bourne shell空白复杂

时间:2017-03-11 06:23:19

标签: shell whitespace

$ 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没有?

1 个答案:

答案 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=quuxprintenv(以及WITH=baz添加到环境中)调用的命令,但是你的PATH上没有名为xyzzy的程序,因此env会给你错误。您可以创建一个程序xyzzy来显示正在发生的事情。

使用数组env,您可以运行:

env "${env[@]}" printenv | …

你得到与#1相同的结果。