在 Bash 裏,能夠經過 export 命令查看當前 Shell 進程的環境變量,這些環境變量一些是 Bash 本身建立的,還有一些是 Bash 從父進程繼承來的,然而須要注意的是,父進程傳給 Bash 的環境變量不必定是咱們想象的那樣。數組
在 C 語言層面,環境變量是存放在一個名爲 environ 的全局變量裏的,這個變量的值是一個字符串的數組,像這樣:bash
{"foo=1", "bar=2"}
在父子孫一輩輩進程中傳遞的就是這麼個數組,咱們嘴裏說的環境變量的原貌其實就是個字符串,而不是咱們一般在高級語言裏看到的鍵值對。然而操做系統並無對環境變量字符串的格式作任何限制,environ 變量的值還能夠是這樣:ide
{"1=1", "=2", "="}
甚至這樣:spa
{"foo\nbar=1"}
Bash 在啓動的時候,會檢查 environ 數組中的每一個字符串,若是它包含 =,且 = 左邊有任意的字符,就把它從 = 分割開,一個作變量名,一個作值,變成本身的變量。咦? "1=1" 也會導入成變量? 是的,在 Bash 的實現當中,是這樣的,只是這樣的變量會被加上特殊的屬性標記。操作系統
變量名稱合法的變量被添加的屬性是: code
att_exported | att_imported
一個表示是要導出給子進程的環境變量,一個表示是從環境變量導入的變量。blog
變量名不合法的變量被添加的屬性是:繼承
att_exported | att_imported | att_invisible
多了一個 invisible 屬性,表示不可見。進程
在 Bash 啓動以後,各個內部命令能夠經過這個標記判斷是否是本身想要的變量。好比 set 命令就不會輸出 1 這個變量:字符串
$ env -i 1=1 bash -c set | grep '1='
|
但 export 命令就會:
$ env -i 1=1 bash -c export declare -x 1 |
declare -x 1 顯然是非法的,甚至還能夠這樣:
$ env -i $'foo\nrm -rf /=' bash -c export declare -x OLDPWD |
看起來頗有風險的樣子,不過目前 Bash 4.4 beta 版本,已經修復了這個問題,export 命令再也不輸出那些變量名不合法的變量了,下面是 export 命令源碼作的改動:
+ /* If we imported a variable that's not a valid identifier, don't + show it in any lists. */ + if ((var->attributes & (att_invisible|att_imported)) == (att_invisible|att_imported)) + continue;
那 Bash 在啓動其餘程序的時候,會把這樣的環境變量傳遞給子進程嗎?答案是會的,咱們能夠經過在兩個 env 命令中間插入一個 bash 命令來看出效果:
$ env -i 1=1 bash -c env PWD=/Users/admin |
Bash 在啓動其餘程序的時候,會把本身全部的變量中帶有 att_exported 屬性且值不是空的變量以及它們的值分別用 = 鏈接起來合成一個字符串數組,從新復值給 environ 變量,也就是作了和啓動時導入環境變量相反的操做。
那些沒有等號或者等號左邊沒有字符的環境變量,由於 Bash 在啓動的時候就丟棄了,因此也就無法傳遞給它的子進程了。