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吧:
1
2
3
|
#! /bin/bash
a=
"hi"
echo
$a
|
我們先來執行一下這個shell腳本,打開終端,敲入: ./file1
結果是什么,你應該也看到了吧:
1
|
bash
: .
/file1
: Permission denied
|
為什么呢。我們先不管這個吧,先看一下,另一個結果:
. ./file1(注意啊,兩個點之間有個空格的哦,要不就成了上一級目錄了,如果你不嫌麻煩的話,也可以寫source ./file1)這個的結果呢,跟前面就不一樣了,正如我們所願的,輸出了hi。
./file1,直接執行,需要另起shell進程,而你似乎還沒有這個權限(這個改一下就OK了,后面再說),而用點命令就不一樣了(注意啊,./file這里的點是當前目錄的意思),點命令會在當前的shell下執行。補充說一下怎么改一下file1的權限,讓我們可以在按shell腳本來執行:
1
|
chmod
+x file1
|
再執行一下./file1,是不是OK了?
再來看另一個例子吧。首先腳本文件file1
1
2
|
#! /bin/bash
a=
"hi"
|
腳本文件file2(與file1在同一個目錄下)
1
2
3
|
#! /bin/bash
.
/file1
echo
$a
|
記得改一下file1的權限啊,要不./file1就沒法執行了。執行一下看看結果。什么都沒有,是吧。我們再改一下file2,這回用一下咱們的點命令
1
2
3
|
#! /bin/bash
. .
/file1
echo
$a
|
怎么樣結果不一樣了吧。這個例子應該還是能說明點問題的吧。如果不用點命令的話,會另起shell進程,而啟動這個進行的時候,它會建立自己的進程環境(暫且這么叫它吧),然后在這個進行結束的時候,它所建立的環境也隨之被銷毀。而且點命令就不一樣了,它會把點命令所帶的shell腳本里的所以內容帶到當前的shell進程里,在本程序里,就是變量a了。
同樣,可以解釋下面這個問題:
為什么在shell腳本里面用export設置環境變量之后,當shell執行完了,用set命令看不到呢?但是你如果直接在終端里export 環境變量用set是看到的。
一個shell腳本test.sh的內容為:
1
2
|
#!/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 命令。