2014-09-27 113 views
3

學習Bash的書提到,一個子shell會只繼承環境variabels和文件描述符,...等等,它不會繼承變量未出口的擊子shell神祕

$ var=15 
$ (echo $var) 
15 
$ ./file # this file include the same command echo $var 

$ 

我所知shell會爲()case和./file創建兩個子shell,但是爲什麼在()情況下subhell會標識var變量,雖然它沒有被導出,在./file的情況下它沒有標識它?

# Strace for() 
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f24558b1a10) = 25617 
# Strace for ./file 
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f24558b1a10) = 25631 

我試圖用strace的弄清楚如何發生和令人驚訝的我發現,bash將使用相同的參數對克隆系統調用,這樣,這意味着在這兩個分叉過程()和./file應有相同的父進程地址空間,所以爲什麼在()情況下變量對子shell是可見的,並且對於./file大小寫也不會發生這種情況,儘管相同的參數是基於克隆系統調用的。

+0

你是怎麼做strace for()的? – 2016-01-22 01:27:03

回答

3

子shell創建腳本調用一樣。此時,來自父shell的變量的處理方式不同:execve()傳遞了一組有意的變量集(腳本調用案例),但未調用execve()(括號的情況下)會使完整的一組變量保持不變。

您使用strace進行的探測應該已經證明了這種差異;如果你沒有看到它,我只能假設你犯了幾個可能的錯誤之一。我會剝奪我所做的顯示差異,然後你可以自己決定你的錯誤在哪裏。

我創建了兩條痕跡。首先是使用

strace -f -o bash-mystery-1.strace bash -c 'v=15; (echo $v)' 

和第二用做

strace -f -o bash-mystery-2.strace bash -c 'v=15; ./x.sh' 

完成(與x.sh是一個可執行的腳本。)

選項-f必要追查父shell的孩子(命令行中的bash)。

這些跟蹤我比較了使用diff -y -W 300均衡像地址的所有典型和常見的差異後的PID:

q() { 
    sed -e 's/0x[0-9a-f]*/ADDR/g' \ 
     -e 's/12923\|12927/PARENT/g' \ 
     -e 's/12924\|12928/CHILD/g' 
} 
diff -y -W 300 <(q < bash-mystery-1.strace) <(q < bash-mystery-2.strace) | less -S 

12923和12927是我的父母PID和12924和12928是我的孩子的PID(我發現了通過掃描跟蹤文件)。你當然會有不同的數字,所以調整這些。而且您需要一個非常寬的終端(超過200個字符)才能正確查看差異輸出。因此,讓你的窗口寬;-)

大約140線我找到clone()調用這是或多或少fork(),所以它將當前進程拆分爲兩個。在那兒,孩子開始做事,就像我們在跟蹤中看到的那樣。在165線附近,我看到了execve()的呼叫,但只是在調用腳本的情況下,因此孩子自願放棄了很多環境並設置了一個故意的環境。圓括號的情況不會改變它的環境(它不會調用execve()),所以子進程繼續有全套設置。

2

你有你的var出口子進程:

export var=15 

導出後,該變量是在推出的時間用於所有兒童的過程(不出口時間)。

var=15 
export var 

是相同

export var 
var=15 

是相同

export var=15 

導出可使用unset被取消。樣品:unset var

+2

這與這個問題有什麼關係? – bobah 2014-09-27 21:52:00

+0

這個問題已經被編輯,因爲我的答案... – 2014-09-27 21:54:59

+2

感謝您的回答,但我想知道情況背後真正發生了什麼 – user3718463 2014-09-27 22:26:58

1

這個神祕的解決方案是,子shell繼承了從包括所有shell變量的母貝,因爲他們僅僅是用叉子或克隆調用,所以它們與父進程相同的內存空間,這就是爲什麼這將工作

$ var=15 
$ (echo $var) 
15 

但在./file,子shell將在後面接着的exec或execv系統調用,將清除所有以前的父變量,但我們仍然有環境變量 你可以看看這個使用strace的使用-f監視子子shell,你會發現有一個呼叫execv

使用括號並 使用 execve()呼籲新工藝
[pid 26387] execve("./file", ["./file"], [/* 75 vars */]) = -1 ENOEXEC (Exec format error) 
+0

你打我5分鐘;-)+¹ – Alfe 2014-09-27 23:21:25

+1

哈哈哈不要介意花花公子^ _ ^,你解釋它比我做得更好,並使之更加清晰 – user3718463 2014-09-27 23:30:15