2017-01-23 57 views
2

爲什麼這項工作:爲什麼你在Bash函數而不是在腳本本身設置環境變量

# a.sh 
setEnv() { 
    export TEST_A='Set' 
} 

時,這並不:

# b.sh 
export TEST_B='Set' 

例:

> source a.sh 
> setEnv 
> env | grep TEST_A 
TEST_A=Set 
> b.sh 
> env | grep TEST_B 

我明白爲什麼運行腳本不起作用以及如何使它工作(source b.sh等),但我很好奇爲什麼t他功能正常。 這是在OS X上,如果有關係。

+1

當您運行腳本時,它會創建一個子shell,並且該變量將在其中定義,但不在父級中。函數調用仍在當前shell中。你也可以'源'另一個腳本。 – karakfa

+4

對稱處理腳本,它可以工作。 'source b.sh'後跟'env | grep TEST_B'會很好。如果你沒有輸入'a.sh',你就沒有這個函數可以運行。這都是關於子shell(運行'b.sh'創建一個新的shell來獲取它的環境設置),而不是(使用'source'不會創建一個新的shell)。 –

回答

4

執行一個函數本身並不像b.sh那樣啓動一個新的進程。

從手冊頁(強調最後一句):

FUNCTIONS 
     A shell function, defined as described above under SHELL GRAMMAR, 
     stores a series of commands for later execution. When the name of a 
     shell function is used as a simple command name, the list of commands 
     associated with that function name is executed. **Functions are executed 
     in the context of the current shell; no new process is created to 
     interpret them (contrast this with the execution of a shell script).** 
5

您需要了解執行腳本採購之間的差異。

  • 採購運行從父 - 殼,其中所述腳本調用腳本;所有環境變量被保留直到父 - 殼被終止(終端被關閉時,或各變量復位或取消),而

  • 執行叉從父殼一個新的外殼,這些變量包括您export變量僅保留在子shell的環境中,並在腳本終止時被銷燬。

即在第一種情況下舉行的變量產生的子shell(想象它是一個環境),在一個單獨的子環境的範圍不分配,但在父母的只是加(如想象的額外的存儲單元,由父級維護)環境,直到您打開會話。但是執行一個腳本就是一個簡單的比喻,調用一個變量存儲在堆棧中的函數,該函數在函數調用結束時釋放範圍。同樣,分叉的shell的環境在其終止時會縮小範圍。

所以它歸結到這一點,即使你有一個功能export您的變量,如果你不source它當前的外殼,只是白了execute它,變量沒有保留;即

# a.sh 
setEnv() { 
    export TEST_A='Set' 
} 

,如果你在shell中運行它作爲

bash script.sh # unlike/NOT source script.sh 
env | grep TEST_A 
        # empty 
+0

他承認在沒有'source'的情況下運行腳本是他的問題。 – chepner

+0

同意@chepner:在這種情況下,讓OP知道他們之間的區別會使他成爲第二個劇本的「源」嗎?你認爲我應該添加一些其他信息嗎? – Inian

+0

問題的關鍵似乎是運行腳本時運行某個函數的原因沒有。 – chepner

3

我明白爲什麼運行該腳本不工作,做什麼,使其工作(source b.sh等)

因此,您已經瞭解,直接執行b.sh - 在子進程中,其變化爲t他根本環境不會給當前過程(殼)可見 - 將定義在當前(殼)工藝TEST_B,所以我們可以把這種情況下出來的畫面。

我很好奇爲什麼該函數可以工作。

  • 當你source一個腳本,您在當前外殼的上下文中執行它 - 嚴格地講,這是因爲如果你已經直接在提示符下輸入腳本的內容:任何更改包括外殼特定元素(如shell變量,別名,函數)對當前shell變得可見。

  • 因此,執行source a.sh後,功能setEnv現已在當前可用的殼,並調用它執行export TEST_A='Set',這在當前殼限定環境變量TEST_A(和隨後創建子進程會看到它)。

  • 也許你誤解是圍繞着chepner's helpful answer地址:在POSIX般的炮彈,功能運行在當前shell - 對比與腳本(當沒有source運行),爲此,子進程已創建。

這是在OS X上,如果該事項。

不是在這種情況下,因爲只有bash本身內置的功能被使用。