形似赋值语句的参数

我们知道,在 Bash 中,当变量出现在一个赋值语句的右侧时,变量只会展开,不会分词,即便变量两边没有引号: 

$ foo="1                       2"

$ bar=$foo # 不会被拆分成 bar=1 和 2 两个词

$ echo "$bar"

1                       2

但是,当一个形似赋值语句的词,作为参数传给一个命令时,这时分词步骤就不会少了:

$ foo="1                       2"

$ printf '%s\n' bar=$foo

bar=1

2

bar=$foo 虽然看起来像是赋值语句,但因为它出现在了命令名称的后面,所以它就是个普通的参数。它会先展开成 bar=1                       2,然后被拆分成 bar=1 和 2 两个参数传给 printf。外部命令也一样:

$ valueOfa="1 b=2"

$ env -i a=$valueOfa env # 你以为传给 env 的第二个参数是 "a=1 b=2",但其实是 "a=1" 和 "b=2" 两个参数

a=1

b=2

可是,有一些命令却是特殊的,比如 alias:

$ valueOfa="1 b=2"

$ alias a=$valueOfa # 传给 alias 命令的会是 "a=1" 和 "b=2" 两个参数?

$ alias

alias a='1 b=2'  # 并不是,valueOfa 这个变量居然没有被分词!

像 alias 这样的内部命令一共有 6 个,分别是:alias、declare、typeset、export、readonly、local,它们的功能都是声明一个什么东西,变量或者别名。Bash 对它们的参数做了特殊对待,如果满足赋值语句的格式,则不对其中的变量进行分词。当然你也可以就把它们看成是赋值语句,反正赋值语句的效果是创建一个变量,这些参数的效果也是创建一个变量(除了 alias 命令)。Bash 手册也直接把它们说成是赋值语句:

Assignment statements may also appear as arguments to the aliasdeclaretypeset,exportreadonly, and local builtin commands. 

在 Bash 的实现里,是专门用一个函数对这样的参数做了特殊处理:

/* This is a hack to suppress word splitting for assignment statements
   given as arguments to builtins with the ASSIGNMENT_BUILTIN flag set. */
static void
fix_assignment_words (words)
     WORD_LIST *words;
{
...

等等,还没完。上面说,如果满足赋值语句的格式,这些参数才会被特殊对待,那如果不满足呢?

我们知道,赋值语句的左边必须是合法的标识符,合法的标识符得符合“字母下划线开头后跟若干个字母数字下划线”。这样的话 1=$foo 就必定不是个合法的赋值语句了,下面试一把:

$ foo="1 2=2"

$ alias 1=$foo

$ alias

alias 1='1'

alias 2='2'

果然,被当成普通的参数了。

posted @ 2015-09-25 06:13  紫云飞  阅读(548)  评论(0编辑  收藏  举报