文章出處

我們知道,在 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'

果然,被當成普通的參數了。


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()