# 【Shell】linux 下source、sh、bash、./執行指令碼的區別

[linux 下source、sh、bash、./執行指令碼的區別 - IT閱讀 (itread01.com)](https://www.itread01.com/content/1548311242.html)

<div id="bkmrk-1%E3%80%81source%E5%91%BD%E4%BB%A4%E7%94%A8%E6%B3%95%EF%BC%9A-%E3%80%80%E3%80%80sour"><div><div>1、source命令用法：</div><div> source FileName</div><div> 作用:在當前bash環境下讀取並執行FileName中的命令。該filename檔案可以無"執行許可權"</div><div> 注：該命令通常用命令“.”來替代。</div><div> 如：source .bash_profile</div><div> . .bash_profile兩者等效。</div><div> source(或點)命令通常用於重新執行剛修改的初始化文件。</div><div> source命令(從 C Shell 而來)是bash shell的內建命令。</div><div> 點命令，就是個點符號，(從Bourne Shell而來)。</div><div> source的程式主體是bash，指令碼中的$0變數的值是bash，而且由於作用於當前bash環境，指令碼中set的變數將直接起效  
 </div><div>2、 sh, bash的命令用法：</div><div> sh/bash FileName</div><div> 作用:開啟一個子shell來讀取並執行FileName中命令。該filename檔案可以無"執行許可權"</div><div> 注：執行一個shell指令碼時會啟動另一個命令直譯器.</div><div> 每個shell指令碼有效地執行在父shell(parent shell)的一個子程序裡.</div><div> 這個父shell是指在一個控制終端或在一個xterm視窗中給你命令指示符的程序.</div><div> shell指令碼也可以啟動他自已的子程序.</div><div> 這些子shell(即子程序)使指令碼並行地，有效率地地同時執行指令碼內的多個子任務.</div><div> 在ubuntu中sh只是bash的一個連結。</div><div> 由於是在子shell中執行，指令碼設定的變數不會影響當前shell。  
 </div><div>3、./的命令用法：</div><div> ./FileName</div><div> 作用:開啟一個子shell來讀取並執行FileName中命令。該filename檔案需要"執行許可權"</div><div> 注：執行一個shell指令碼時會啟動另一個命令直譯器.</div><div> 每個shell指令碼有效地執行在父shell(parent shell)的一個子程序裡.</div><div> 這個父shell是指在一個控制終端或在一個xterm視窗中給你命令指示符的程序.</div><div> shell指令碼也可以啟動他自已的子程序.</div><div> 這些子shell(即子程序)使指令碼並行地，有效率地地同時執行指令碼內的多個子任務.</div><div> 由於是在子shell中執行，指令碼設定的變數不會影響當前shell。</div><div>exec和source都屬於bash內部命令（builtins commands），在bash下輸入man exec或man source可以檢視所有的內部命令資訊。</div></div></div>bash shell的命令分為兩類：外部命令和內部命令。外部命令是通過系統呼叫或獨立的程式實現的，如sed、awk等等。內部命令是由特殊的檔案格式（.def）所實現，如cd、history、exec等等。

在說明exe和source的區別之前，先說明一下fork的概念。

fork是linux的系統呼叫，用來建立子程序（child process）。子程序是父程序(parent process)的一個副本，從父程序那裡獲得一定的資源分配以及繼承父程序的環境。子程序與父程序唯一不同的地方在於pid（process id）。

環境變數（傳給子程序的變數，遺傳性是本地變數和環境變數的根本區別）只能單向從父程序傳給子程序。不管子程序的環境變數如何變化，都不會影響父程序的環境變數。

<div id="bkmrk-"><div><div></div></div></div>shell script:

<div id="bkmrk-%E6%9C%89%E5%85%A9%E7%A8%AE%E6%96%B9%E6%B3%95%E5%9F%B7%E8%A1%8Cshell%C2%A0scripts"><div><div>有兩種方法執行shell scripts，一種是新產生一個shell，然後執行相應的shell scripts；一種是在當前shell下執行，不再啟用其他shell。  
新產生一個shell然後再執行scripts的方法是在scripts檔案開頭加入以下語句  
\#!/bin/sh  
一般的script檔案(.sh)即是這種用法。這種方法先啟用新的sub-shell（新的子程序）,然後在其下執行命令。  
另外一種方法就是上面說過的source命令，不再產生新的shell，而在當前shell下執行一切命令。</div></div></div>source:

source命令即點(.)命令。

在bash下輸入man source，找到source命令解釋處，可以看到解釋"Read and execute commands from filename in the current shell environment and ..."。從中可以知道，source命令是在當前程序中執行引數檔案中的各個命令，而不是另起子程序(或sub-shell)。

<div id="bkmrk--0"><div><div></div></div></div>exec:

在bash下輸入man exec，找到exec命令解釋處，可以看到有"No new process is created."這樣的解釋，這就是說exec命令不產生新的子程序。那麼exec與source的區別是什麼呢？

<div id="bkmrk-exec%E5%91%BD%E4%BB%A4%E5%9C%A8%E5%9F%B7%E8%A1%8C%E6%99%82%E6%9C%83%E6%8A%8A%E7%95%B6%E5%89%8D%E7%9A%84shell"><div><div>**exec命令在執行時會把當前的shell process關閉，然後換到後面的命令繼續執行。**  
  
</div></div></div>\* fork ( /directory/script.sh)  
 fork是最普通的, 就是直接在腳本里面用/directory/script.sh來呼叫script.sh這個指令碼.執行的時候開一個sub-shell執行呼叫的指令碼，sub-shell執行的時候, parent-shell還在。sub-shell執行完畢後返回parent-shell. sub-shell從parent-shell繼承環境變數.但是sub-shell中的環境變數不會帶回parent-shell  
\* source (source /directory/script.sh)  
 與fork的區別是不新開一個sub-shell來執行被呼叫的指令碼，而是在同一個shell中執行. 所以被呼叫的指令碼中宣告的變數和環境變數, 都可以在主指令碼中得到和使用.  
\* exec (exec /directory/script.sh)  
 exec與fork不同，不需要新開一個sub-shell來執行被呼叫的指令碼. 被呼叫的指令碼與父指令碼在同一個shell內執行。但是使用exec呼叫一個新指令碼以後, 父指令碼中exec行之後的內容就不會再執行了。這是exec和source的區別。

下面用一個例子來講解

1.sh

```shell
#!/bin/bash  

A=B  

echo "PID for 1.sh before exec/source/fork:$"  
export A  

echo "1.sh: \$A is $A"  

case $1 in  
        exec)  
                echo "using exec..."  
                exec ./2.sh ;;  
        source)  
                echo "using source..."  
                . ./2.sh ;;  
        *)  
                echo "using fork by default..."  
                ./2.sh ;;  
esac  

echo "PID for 1.sh after exec/source/fork:$"  
echo "1.sh: \$A is $A"  
```

2.sh

```shell

#!/bin/bash  

echo "PID for 2.sh: $"  
echo "2.sh get \$A=$A from 1.sh"  

A=C  

export A  

echo "2.sh: \$A is $A"  
```

<div id="bkmrk-%E4%B8%8B%E9%9D%A2%E5%9C%A8%E5%91%BD%E4%BB%A4%E5%88%97%E4%B8%AD%E5%8E%BB%E5%9F%B7%E8%A1%8C"><div>下面在命令列中去執行</div></div>./1.sh fork

[![image-1645383274668.png](https://bookstack.treemanou.com/uploads/images/gallery/2022-02/scaled-1680-/YdsokHYuj7W3z5Ib-image-1645383274668.png)](https://bookstack.treemanou.com/uploads/images/gallery/2022-02/YdsokHYuj7W3z5Ib-image-1645383274668.png)

可以看到，1.sh是在父程序中執行，2.sh是在子程序中執行的，父程序的PID是5344，而子程序的是5345，當子程序執行完畢後，控制權返回到父程序。同時，在子程序改變環境變數A的值不會影響到父程序。

./1.sh source

[![image-1645383287482.png](https://bookstack.treemanou.com/uploads/images/gallery/2022-02/scaled-1680-/tOSV4Em25BecrFxb-image-1645383287482.png)](https://bookstack.treemanou.com/uploads/images/gallery/2022-02/tOSV4Em25BecrFxb-image-1645383287482.png)

由結果可知，1.sh和2.sh都是在同一程序中執行的，PID為5367

./1.sh exec

[![image-1645383299760.png](https://bookstack.treemanou.com/uploads/images/gallery/2022-02/scaled-1680-/tvf4pSNRddzmZj05-image-1645383299760.png)](https://bookstack.treemanou.com/uploads/images/gallery/2022-02/tvf4pSNRddzmZj05-image-1645383299760.png)

可知，兩個指令碼都是在同一程序中執行，但是請注意，使用exec終止了原來的父程序，因此，可以看到

```shell
echo "PID for 1.sh after exec/source/fork:$"  

echo "1.sh: \$A is $A"  
```

這兩個命令沒有執行

由這個例子，便大致可瞭解它們的區別了

<center id="bkmrk--4"></center>