文章出處

上文中曾說到:

  • 所謂的環境變量的真實面目其實就是個任意字符串
  • Bash 在啟動時會將 environ 數組中包含 = 號的字符串導入成為自己的變量
  • Bash 在啟動外部命令時會將自己內部標記為環境變量的變量重組成字符串數組賦值給 environ

本文中繼續深入講三點:

  • environ 數組中可能存在 = 左邊名字相同的元素,也就是同名的環境變量,Bash 是怎么導入的?
  • Bash 還可以從環境變量中導入函數,甚至同時導入兩個同名的變量和函數
  • Bash 還可以同時導出兩個同名的變量和函數

如果有兩個同名的環境變量,很簡單,那么后面的值會覆蓋前面的:

$ env foo=1 foo=2 bash -c 'echo $foo'

2

上篇文章中我們沒有提到過函數,Bash 其實是可以從環境變量中導入函數的,比如下面這樣:

$ foo() { echo foo函數; }

$ export -f foo

$ bash

$ foo

foo函數

上一級的 Shell 把函數傳給了它的 child shell,Bash 是怎么實現的呢?我們用 env 命令演示一下:

$ env 'BASH_FUNC_foo%%=() { echo foo函數; }' bash -c 'foo'

foo函數

其實 Bash 就是把滿足 "BASH_FUNC_函數名%%=(){ 函數體" 格式的環境變量作為函數源碼解析并導入。所以兩個同名的變量和函數并不會沖突,可以同時導入,像這樣:

$ env 'foo=1' 'BASH_FUNC_foo%%=() { echo $1; }' bash -c 'foo $foo'

1

既然可以同時導入,那么導出更沒問題了:

$ foo=1

$ foo(){ echo foo函數; }

$ export foo;export -f foo

$ env

...

foo=1

BASH_FUNC_foo%%=() { echo foo函數

}

...

Bash 4.3.30 之前的版本

注意,本文所講的表現僅適用于 Bash 4.3.30 及之后的版本,之前的 Bash 版本在導出函數時不會給函數名加上 BASH_FUNC_ 前綴和 %% 后綴,在導入時也不會識別前綴后綴,只要看到 = 右邊是 "() {" 這四個字符,就按函數導入,像這樣:

$ env 'foo=() { echo foo函數; }' bash -c 'foo'

foo函數

由于環境變量字符串的轉換和識別規則不同,假如你在 Bash 4.3.30 中打開一個 Bash 3.2.25,后者是無法繼承到前者導出的函數的:

$ bash4.3.30

$ foo() { echo foo函數 ; }

$ export -f foo

$ bash3.2.25

$ foo

bash3.2.25: foo: command not found

反之亦然,同時 foo 會被導入成一個變量:

$ bash3.2.25

$ foo() { echo foo函數 ; }

$ export -f foo

$ bash4.3.30

$ foo

bash3.2.25: foo: command not found

$ echo $foo

() { echo foo函數 }


文章列表




Avast logo

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


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

    IT工程師數位筆記本

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