1. 程式人生 > >父 shell,子 shell ,export 與 變數傳遞

父 shell,子 shell ,export 與 變數傳遞

在我們所執行的腳本里,我們還可以啟動新的子 shell 程序,這些子 shell 程序使指令碼並行地執行著多個子任務。一般而言,在一個腳本里執行一個外部命令(普通的可執行檔案)時,shell 會 fork 出一個子程序,然後再用 exec 來執行這個程式;但是,bash shell 的內建命令(builtin)卻不會這樣,它們是直接執行的。所以,等價的內建命令的執行速度會比執行外部命令要來的快。

在一對括號 (...) 裡可以放置一組指令,這些指令是在一個子 shell 裡執行的。在子 shell 裡的變數不能被這段子 shell 外的程式碼直接訪問,也就是說子 shell 裡的變數不能被父 shell 所存取,實際上它們是區域性變數。這裡可以參考:

Link (( ))和 [[ ]]Link shell 與 命令的執行 這兩篇文章。

下面用一段程式碼進行測試:

#!/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

執行輸出:

[email protected]:~/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”。也就是說,區域性變數不能被外部程式碼所訪問。

從輸出可以看到,在子 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 裡的一個副本。

說到父shell 和 子 shell,那麼會想到 export 這個命令。export 也是 bash 的一個內建命令。它主要是用來將父 shell 裡的變數匯出供子 shell 使用。它有如下特徵:1. 用 export 匯出的變數放在“匯出變數列表”中,它可以被子 shell (子 shell 的子 shell 也是如此)拷貝並使用。2. 被 export 出來的變數雖然可以被子 shell 使用,但它也只是一個拷貝,而不會影響到父 shell 中的值以及其它子 shell 中的值。

看下面示例;

  1. 先在當前 shell 裡 export 一個變數:

    [email protected]:~/shell$ export exp8temp="hello world"
    [email protected]:~/shell$ echo $exp8temp
    hello world
    
  2. 執行一個指令碼 echo 此變數(該指令碼只有一句話即 echo $exp8temp ):

    $ ./exp8.sh
    hello world
    

由上可見,父 shell 裡 export 的變數可以被子 shell 讀取。

  1. 測試一下子 shell 更改此變數是否會影響父 shell 裡的值,子 shell 程式碼如下:

    #!/bin/bash
    
    exp8temp="hello shell"
    
    echo $exp8temp
    

檢驗上面的情景:

[email protected]:~/shell$ ./exp8.sh
hello shell
[email protected]:~/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 傳遞自己的變數嗎?下面方法可以考慮:

  1. 通過一箇中間檔案進行:

    #!/bin/bash
    
    (
     subvar="hello shell"
     echo "$subvar" > temp.txt
    )
    
    read pvar < temp.txt
    
    echo $pvar
    
    執行輸出:
    $ sh subandp.sh
    hello shell
    
  2. 通過命令替換:

    #!/bin/bash
    
    pvar=`subvar="hello shell";echo $subvar`
    
    echo $pvar
    
執行輸出: ::
$ ./subandp.shhello shell

執行命令替換符(兩個反單引號)之間的命令也是在子 shell 來完成的。

  1. 使用命名管道:

    #!/bin/bash
    
    mkfifo -m 777 npipe
    
    (
      subsend="hello world"
      echo "$subsend" > npipe &
     )
    
    read pread < npipe
    
    echo "$pread"
    
    exit 0
    

執行輸出:

[email protected]:~/shell$ ./var.sh
hello world

關於有名管道建立命令 mkfifo 可參考:http://www.groad.net/bbs/read.php?tid-3707.html

  1. 使用 here 文件:

    #!/bin/bash
    
    read pvar << HERE
    `subvar="hello shell"
    echo $subvar`
    HERE
    
    echo $pvar
    

執行輸出:

$ ./subandp.sh
hello shell

方法應該還有很多,這些方法的本質原理基於程序間的通訊。

轉載自:


相關推薦

shell shell export 變數傳遞

在我們所執行的腳本里,我們還可以啟動新的子 shell 程序,這些子 shell 程序使指令碼並行地執行著多個子任務。一般而言,在一個腳本里執行一個外部命令(普通的可執行檔案)時,shell 會 fork 出一個子程序,然後再用 exec 來執行這個程式;但是,bash shell 的內建命令(builti

Linux編程 9 (shell類型shell父子關系shell用法)

需要 cli 返回 root 查看 centos 7 bsh 其它 amp 一. shell類型   1.1 交互式 bin/ shell程序     當用戶登錄到某個虛擬控制臺終端或是在GUI中啟動終端仿真器時,默認的shell程序就會開始運行。系統啟動什麽樣的shel

Linux程式設計 9 (shell型別shell父子關係shell用法)

一. shell型別   1.1  互動式 bin/ shell程式     當用戶登入到某個虛擬控制檯終端或是在GUI中啟動終端模擬器時,預設的shell程式就會開始執行。系統啟動什麼樣的shell程式取決於你個人的使用者ID配置,在etc/passwd檔案中。如下圖所示,root使用者使用bash she

JQuery 各節點獲取函數:節點節點兄弟節點

集合 exp pos 完全 children content 文本 內容 clas jQuery.parent(expr) //找父元素 jQuery.parents(expr) //找到所有祖先元素,不限於父元素 jQuery.chi

Vue.js如何獲得兄弟元素元素元素(DOM操作)

<button @click = “clickfun($event)”>點選</button> methods: { clickfun(e) { // e.target 是你當前點選的元素 // e.currentTarget 是你繫結事件的元素 } }, #獲得點選元素的

Vue.js 獲得兄弟元素元素元素(DOM操作)

pre lin col bsp 操作 attr current 綁定 tar   e.target 是你當前點擊的元素 e.currentTarget 是你綁定事件的元素 e.currentTarget.previousEle

windows視窗分析視窗視窗所有者視窗

https://blog.csdn.net/u010983763/article/details/53636831 在Windows應用程式中,視窗是通過控制代碼HWND來標識的,我們要對某個視窗進行操作,首先就要獲取到這個視窗的控制代碼,這就是視窗和控制代碼的聯絡。 (本文嘗試通過一些簡單

html dom節點節點兄弟節點

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head

JAVA中內部類

一個.java原始檔中可以有多個類(不包含內部類),但是隻有一個類是Public的,如 public class Test {  public class A{//內部類  }  public class B{//內部類  } // /** //  * @param arg

vue元件呼叫元件元件傳值prop用法

1.父元件呼叫子元件 子元件children.vue程式碼如下: <template> <div>我是子元件</div> </template> 父元件parent.vue程式碼如下: <template>

Jquery找元素祖先元素子孫兄弟節點

jQuery.parent(expr)           //找父元素 jQuery.parents(expr)          //找到所有祖先元素,不限於父元素 jQuery.children(expr)        //查詢所有子元素,只會找到直接的孩子節點,不會返回所有子孫 jQuery.co

js對節點的操作新增刪除獲得節點節點兄弟節點

<pre name="code" class="javascript">var chils= s.childNodes; //得到s的全部子節點 var par=s.parentNod

視窗開啟視窗視窗關閉後自動重新整理視窗

可以在任何地方插入程式碼 <script language="javascript"> window.onunload = function(){ window.opener.locat

部署AD林根域域樹

com png 一個 安裝 分享 樹根 sha 新的 oss 林,域樹,子域之間的聯系 首先無論是林根域,子域,域樹,必須要有一個靜態的ip地址,DNS必須指向林根域的ip地址。互相之間必須連通。創建時與安裝AD域步驟大多數一樣創建他們之間的區別是這樣的1、創建林根域

mysql資料庫的多表查詢查詢聯合查詢

/*多表查詢*//*交叉連線*(表1條數*表2條數)*/SELECT * FROM emp JOIN dept;/*內連線(在交叉連線基礎上加條件)*/SELECT * FROM emp JOIN dept ON deptid=id;SELECT * FROM emp JOIN dept ON emp.dep

【CodeForces - 266C】Below the Diagonal (遞迴問題貪心模擬)

題幹: You are given a square matrix consisting of n rows and n columns. We assume that the rows are numbered from 1 to

mysql連線查詢查詢聯合查詢

一、連線查詢(多表查詢) emp表 dept表 1.交叉連線 實際上,交叉連線是將兩個表不設定任何條件的連線結果。 交叉連線通常也被叫做“笛卡爾積”——數學上可能比較多。 語法: from  表1  [cross]  join  表2  

mysql連接查詢查詢聯合查詢

mysql 應該 等於 outer 重復項 左連接 卡爾 nio round 一、連接查詢(多表查詢) emp表 dept表 1.交叉連接 實際上,交叉連接是將兩個表不設定任何條件的連接結果。 交叉連接通常也被叫做“笛卡爾積”——數學上可能比較多。 語法: from

降取樣過取樣欠取樣取樣下采樣上取樣你學會了嗎?【總結】

降取樣:2048HZ對訊號來說是過取樣了,事實上只要訊號不混疊就好(滿足尼奎斯特取樣定理),所以可以對過取樣的訊號作抽取,即是所謂的“降取樣”。在現場中取樣往往受具體條件的限止,或者不存在300HZ的取樣率,或除錯非常困難等等。若R>>1,則Rfs/2就遠大於音

c# XML讀取建立修改節點節點和值

在c#端使用XML。 //建立  public void CreateXmlFile()     {         XmlDocument xmlDoc = new XmlDocument();         //建立型別宣告節點             XmlNode