咱们知道,在 Bash 中,当变量出如今一个赋值语句的右侧时,变量只会展开,不会分词,即使变量两边没有引号: 面试
$ foo="1 2"app $ bar=$foo # 不会被拆分红 bar=1 和 2 两个词函数 $ echo "$bar"ui 1 2spa |
可是,当一个形似赋值语句的词,做为参数传给一个命令时,这时分词步骤就不会少了:code
$ foo="1 2"blog $ printf '%s\n' bar=$fooit bar=1table 2class |
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
alias
,declare
,typeset
,export
,readonly
, andlocal
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' |
果真,被当成普通的参数了。