shell中的點命令與source命令的區別

工程師WWW發表於2014-02-27

1 shell指令碼執行方法

有兩種方法執行shell scripts,一種是新產生一個shell,然後執行相應的shell scripts;一種是在當前shell下執行,不再啟用其他shell。
新產生一個shell然後再執行scripts的方法是在scripts檔案開頭加入語句:#!/bin/sh。一般的script檔案(.sh)即是這種用法。這種方法先啟用新的sub-shell(新的子程式),然後在其下執行命令。
另外一種方法就是上面說過的source命令,不再產生新的shell,而在當前shell下執行一切命令。source: source命令即點(.)命令。在 bash下輸入man source,找到source命令解釋處,可以看到解釋"Read and execute commands from filename in the current shell environment and ..."。從中可以知道,
source命令是在當前程式中執行引數檔案中的各個命令,而不是另起子程式(或sub-shell)。


2 source與點命令

  • source 命令是 bash shell 的內建命令,從 C Shell 而來。
  • source 命令的另一種寫法是點符號,用法和 source 相同,從Bourne Shell而來。
  • source 命令可以強行讓一個指令碼去立即影響當前的環境。
  • source 命令會強制執行指令碼中的全部命令,而忽略檔案的許可權。
  • source 命令通常用於重新執行剛修改的初始化檔案,如 .bash_profile 和 .profile 等等。
  • source 命令可以影響執行指令碼的父shell的環境,而 export 則只能影響其子shell的環境。

使用方法舉例:
$source ~/.bashrc 或者:$. ~/.bashrc
執行後 ~/.bashrc 中的內容立即生效。

source命令(從 C Shell 而來)是bash shell的內建命令。點命令,就是個點符號,(從Bourne Shell而來)是source的另一名稱。同樣的,當前指令碼中設定的變數也將作為指令碼的環境,source(或點)命令通常用於重新執行剛修改的初始化檔案,如 .bash_profile 和 .profile 等等。例如,如果在登入後對 .bash_profile 中的 EDITER 和 TERM 變數做了修改,則能用source命令重新執行 .bash_profile 中的命令而不用登出並重新登入。
source命令的作用就是用來執行一個指令碼,那麼:source a.sh 同直接執行 ./a.sh 有什麼不同呢,比如你在一個指令碼里export $KKK=111 ,如果你用./a.sh執行該指令碼,執行完畢後,你執行 echo $KKK ,發現沒有值,如果你用source來執行,然後再echo ,就會發現KKK=111。因為呼叫./a.sh來執行shell是在一個子shell裡執行的,所以執行後,結果並沒有反應到父shell裡,不過source不同,他就是在本shell中執行的,所以能看到結果。
source命令是shell的一個內部命令,它從指定的shell 檔案中讀入所有命令語句並在當前程式中執行。 因此當多個shell程式(父子程式或無關程式均可)共享一組變數值時,就可以將這些變數賦值語句定義到一個shell檔案裡,並在需要這些變數值的程式中使用點語句來引用這個shell檔案,從而實現變數值共享(對這些變數值的修改僅涉及到這個shell檔案)。但要注意的是,這個shell檔案不能包括含有位置引數的語句,即不能接受$1、$2等命令列引數。
從上面可以看出,其實點命令相當於c語言裡面的#include。下面我們將舉例來說明。
我們先寫一個簡單的shell指令碼檔案,暫且命名為file1吧:
#! /bin/bash a="hi" echo $a
我們先來執行一下這個shell指令碼,開啟終端,敲入: ./file1
結果是什麼,你應該也看到了吧:
bash: ./file1: Permission denied
為什麼呢。我們先不管這個吧,先看一下,另一個結果:
. ./file1(注意啊,兩個點之間有個空格的哦,要不就成了上一級目錄了,如果你不嫌麻煩的話,也可以寫source ./file1)這個的結果呢,跟前面就不一樣了,正如我們所願的,輸出了hi。
./file1,直接執行,需要另起shell程式,而你似乎還沒有這個許可權(這個改一下就OK了,後面再說),而用點命令就不一樣了(注意啊,./file這裡的點是當前目錄的意思),點命令會在當前的shell下執行。補充說一下怎麼改一下file1的許可權,讓我們可以在按shell指令碼來執行:
chmod +x file1
再執行一下./file1,是不是OK了?
再來看另一個例子吧。首先指令碼檔案file1
#! /bin/bash a="hi"
指令碼檔案file2(與file1在同一個目錄下)
#! /bin/bash ./file1 echo $a
記得改一下file1的許可權啊,要不./file1就沒法執行了。執行一下看看結果。什麼都沒有,是吧。我們再改一下file2,這回用一下我們們的點命令
#! /bin/bash . ./file1 echo $a
怎麼樣結果不一樣了吧。這個例子應該還是能說明點問題的吧。如果不用點命令的話,會另起shell程式,而啟動這個進行的時候,它會建立自己的程式環境(暫且這麼叫它吧),然後在這個進行結束的時候,它所建立的環境也隨之被銷燬。而且點命令就不一樣了,它會把點命令所帶的shell指令碼里的所以內容帶到當前的shell程式裡,在本程式裡,就是變數a了。

同樣,可以解釋下面這個問題:
為什麼在shell指令碼里面用export設定環境變數之後,當shell執行完了,用set命令看不到呢?但是你如果直接在終端裡export 環境變數用set是看到的。
一個shell指令碼test.sh的內容為:
#!/bin/bash export AA=123
當我們執行test.sh的時候,是當前終端所在的shell fork一個子shell然後執行test.sh的,執行完了再返回終端所在的shell。明白這點,就容易理解了,我們在test.sh設定了AA環境變數,它只在fork出來的這個子shell中生效,子shell只能繼承父shell的環境變數,而不能修改父shell的環境變數,所以test.sh結束後,父程式的環境就覆蓋回去。所以在test.sh之後完之後,我們用set命令是看不了AA這個環境變數的值的。
那有什麼辦法可以讓指令碼的環境變數在指令碼執行之後仍然對當前終端存在呢?用sorcue 或者.(dot) 。明確告訴shell不要fork執行指令碼,而是在當前的shell執行,這樣環境變數就可以儲存下來了。

source命令與shell scripts的區別是:

source在當前bash環境下執行命令,而scripts是啟動一個子shell來執行命令。這樣如果把設定環境變數(或alias等等)的命令寫進scripts中,就只會影響子shell,無法改變當前的BASH,所以通過檔案(命令列)設定環境變數時,要用source 命令

相關文章