當咱們在一個 shell 裏運行一個腳本程序時,該 shell 就會 fork 出一個新進程,從而啓動了另外一個命令解釋器(由腳本中第一行的 #!/bin/xxx 指定,如 bash shell)來解釋運行咱們這個腳本。也就是說,這個新進程是一個子 shell,而以前的 shell 是個父 shell 。php
在咱們所運行的腳本里,咱們還能夠啓動新的子 shell 進程,這些子 shell 進程使腳本並行地運行着多個子任務。通常而言,在一個腳本里執行一個外部命令(普通的可執行文件)時,shell 會 fork 出一個子進程,而後再用 exec 來執行這個程序;可是,bash shell 的內置命令(builtin)卻不會這樣,它們是直接執行的。因此,等價的內置命令的執行速度會比執行外部命令要來的快。html
在一對括號 (...) 裏能夠放置一組指令,這些指令是在一個子 shell 裏執行的。在子 shell 裏的變量不能被這段子 shell 外的代碼直接訪問,也就是說子 shell 裏的變量不能被父 shell 所存取,實際上它們是局部變量。這裏能夠參考:Link (( ))和 [[ ]]和Link shell 與 命令的執行 這兩篇文章。shell
下面用一段代碼進行測試:bash
#!/bin/bash echo "Subshell level = $BASH_SUBSHELL" outer_variable=Outer outer_variable2=Outer2 ( echo "Subshell level INSIDE subshell = $BASH_SUBSHELL" inner_variable=Inner outer_variable2=Outer_var_changein_subshell echo "From Subshell,\"inner_variable\"=$inner_variable" echo "From parent shell,\"outer\"=$outer_variable" echo "From parent shell, \"outer\"=$outer_variable2" ) echo "In parent shell, check \"outer_variable\" value:$outer_variable" echo "In parent shell, check \"outer_variable2\" value:$outer_variable2" echo echo "Subshell level OUTSIDE subshell = $BASH_SUBSHELL" echo if [ -z "$inner_variable" ] then echo "inner_variable undefined in main body of shell" else echo "From main body of shell,\"inner_variable\"=$inner_variable" fi exit 0
運行輸出:函數
beyes@debian:~/shell$ ./subshell.sh Subshell level = 0 Subshell level INSIDE subshell = 1 From Subshell,"inner_variable"=Inner From parent shell,"outer"=Outer From parent shell, "outer"=Outer_var_changein_subshell In parent shell, check "outer_variable" value:Outer In parent shell, check "outer_variable2" value:Outer2 Subshell level OUTSIDE subshell = 0 inner_variable undefined in main body of shell
在上面的代碼中,BASH_SUBSHELL 是一個環境變量,它表示進入子 shell 的層級,好比處於當前 shell 時,該變量值爲 0;當在當前 shell 派生的子 shell 裏時,該變量值爲 1;若是該子 shell 又派生出一個子 shell,那麼該變量在此間的值就爲 3,以此類推。測試
在代碼中,( ) 裏的代碼段是在子 shell 裏執行的,而 inner_variable 做爲局部變量,它的值能夠在 ( ) 這段代碼裏 echo 出來,可是一旦返回到父shell 時,它就是未定義的,因此會輸出「 inner_variable undefined in main body of shell」。也就是說,局部變量不能被外部代碼所訪問。ui
從輸出能夠看到,在子 shell 中和父 shell 中變量 outer_variable 的輸出值是同樣的;相對應的 outer_variable2 變量即便在子 shell 中進行了修改,可是當返回到父 shell 對其輸出時,它卻仍是父 shell 中原來所賦的值。從這裏能夠看出,子 shell 能夠 「感知」 父 shell 中的變量,但它不能修改它。其本質的緣由和 fork() 函數的原理有關。在 UNIX/LINUX 中,fork 出來的子進程其實是對父進程的一種拷貝,而子 shell 就是父shell fork 出來的一個子進程,因此它理所固然的有了父shell 中的一片拷貝。因此,子 shell 裏的 outer_variable 和 outer_variable2 變量雖然和父 shell 的同名,但它們並非同一個變量,而是父 shell 裏的一個副本。.net
說到父shell 和 子 shell,那麼會想到 export 這個命令。export 也是 bash 的一個內置命令。它主要是用來將父 shell 裏的變量導出供子 shell 使用。它有以下特徵:1. 用 export 導出的變量放在「導出變量列表」中,它能夠被子 shell (子 shell 的子 shell 也是如此)拷貝並使用。2. 被 export 出來的變量雖然能夠被子 shell 使用,但它也只是一個拷貝,而不會影響到父 shell 中的值以及其它子 shell 中的值。htm
看下面示例;繼承
先在當前 shell 裏 export 一個變量:
beyes@debian:~/shell$ export exp8temp="hello world" beyes@debian:~/shell$ echo $exp8temp hello world
運行一個腳本 echo 此變量(該腳本只有一句話即 echo $exp8temp ):
$ ./exp8.sh hello world
由上可見,父 shell 裏 export 的變量能夠被子 shell 讀取。
測試一會兒 shell 更改此變量是否會影響父 shell 裏的值,子 shell 代碼以下:
#!/bin/bash exp8temp="hello shell" echo $exp8temp
檢驗上面的情景:
beyes@debian:~/shell$ ./exp8.sh hello shell beyes@debian:~/shell$ echo $exp8temp hello world
可見子 shell 對父 shell 裏 export 出來的變量進行修改並不能影響到父 shell。這說明了,子 shell 只是在「導出變量列表「裏對該變量進行了一個拷貝。但反過來,父shell再次更改此變量時,子 shell 再去讀時,讀到的是新值,而不是原來的值。
4. 若是在子 shell 裏 export 出的變量,父 shell 是否能讀到呢?先將下面一段代碼放在後臺運行:
#!/bin/bash export exp9temp="hello world" sleep 30 exit 0
而後在在 30 秒內在父 shell 裏讀取一下 $exp9temp 的值,發現輸出爲空。因此咱們得出結論,export 出來的變量不能導出到父進程或者是父進程的環境裏。一個本身稱能夠繼承父進程的東西,而不能反過來去影響父進程。
那麼子 shell 有什麼辦法能夠向父 shell 傳遞本身的變量嗎?下面方法能夠考慮:
經過一箇中間文件進行:
#!/bin/bash ( subvar="hello shell" echo "$subvar" > temp.txt ) read pvar < temp.txt echo $pvar 運行輸出: $ sh subandp.sh hello shell
經過命令替換:
#!/bin/bash pvar=`subvar="hello shell";echo $subvar` echo $pvar
運行輸出: ::
$ ./subandp.shhello shell
執行命令替換符(兩個反單引號)之間的命令也是在子 shell 來完成的。
使用命名管道:
#!/bin/bash mkfifo -m 777 npipe ( subsend="hello world" echo "$subsend" > npipe & ) read pread < npipe echo "$pread" exit 0
運行輸出:
beyes@debian:~/shell$ ./var.sh hello world
關於有名管道建立命令 mkfifo 可參考:http://www.groad.net/bbs/read.php?tid-3707.html
使用 here 文檔:
#!/bin/bash read pvar << HERE `subvar="hello shell" echo $subvar` HERE echo $pvar
運行輸出:
$ ./subandp.sh hello shell
方法應該還有不少,這些方法的本質原理基於進程間的通訊。