Bash 是如何從環境變量中導入函數的

上文中曾說到:html

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

本文中繼續深刻講三點:shell

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

若是有兩個同名的環境變量,很簡單,那麼後面的值會覆蓋前面的:數組

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

2函數

上篇文章中咱們沒有提到過函數,Bash 實際上是能夠從環境變量中導入函數的,好比下面這樣:htm

$ foo() { echo foo函數; }blog

$ export -f foo繼承

$ bash字符串

$ fooget

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函數 }

相關文章
相關標籤/搜索