1. 程式人生 > >#!/bin/bash和#!/bin/sh的區別,source命令和exec命令

#!/bin/bash和#!/bin/sh的區別,source命令和exec命令

Linux指令碼開頭#!/bin/bash和#!/bin/sh是什麼意思以及區別


一、含義


#!/bin/sh是指此指令碼使用/bin/sh來解釋執行,#!是特殊的表示符,其後面根的是此解釋此指令碼的shell的路徑。


其實第一句的#!是對指令碼的直譯器程式路徑,指令碼的內容是由直譯器解釋的,我們可以用各種各樣的直譯器來寫對應的指令碼。


比如說/bin/csh指令碼,/bin/perl指令碼,/bin/awk指令碼,/bin/sed指令碼,甚至/bin/echo等等。


#!/bin/bash同理。


二、區別


GNU/Linux作業系統中的/bin/sh本是bash (Bourne-Again Shell) 的符號連結,但鑑於bash過於複雜,有人把bash從NetBSD移植到Linux並更名為dash (Debian Almquist Shell),並建議將/bin/sh指向它,以獲得更快的指令碼執行速度。Dash Shell 比Bash Shell小的多,符合POSIX標準。


Ubuntu繼承了Debian,所以從Ubuntu 6.10開始預設是Dash Shell。


應該說,/bin/sh與/bin/bash雖然大體上沒什麼區別,但仍存在不同的標準。標記為#!/bin/sh的指令碼不應使用任何POSIX沒有規定的特性 (如let等命令, 但#!/bin/bash可以)。Debian曾經採用/bin/bash更改/bin/dash,目的使用更少的磁碟空間、提供較少的功能、獲取更快的速度。但是後來經過shell指令碼測試存在執行問題。因為原先在bash shell下可以執行的shell script (shell 指令碼),在/bin/sh下還是會出現一些意想不到的問題,不是100%的兼用。


上面可以這樣理解,使用man sh命令和man bash命令去觀察,可以發現sh本身就是dash,也就更好的說明整合Debian系統之後的更改。


補充
指令碼test.sh內容:
#!/bin/sh
source pcy.sh #pcy.sh並不存在
echo hello
執行./test.sh,螢幕輸出為:
./test.sh: line 2: pcy.sh: No such file or directory
由此可見,在#!/bin/sh的情況下,source不成功,不會執行source後面的程式碼。
修改test.sh指令碼的第一行,變為#!/bin/bash,再次執行./test.sh,螢幕輸出為:
./test.sh: line 2: pcy.sh: No such file or directory
hello
由此可見,在#!/bin/bash的情況下,雖然source不成功,但是還是運行了source後面的echo語句。
但是緊接著我又試著運行了一下sh ./test.sh,這次螢幕輸出為:
./test.sh: line 2: pcy.sh: No such file or directory
表示雖然指令碼中指定了#!/bin/bash,但是如果使用sh 方式執行,如果source不成功,也不會執行source後面的程式碼。






Linux source命令:


通常用法:source filepath 或 . filepath


功能:使當前shell讀入路徑為filepath的shell檔案並依次執行檔案中的所有語句,通常用於重新執行剛修改的初始化檔案,使之立即生效,而不必登出並重新登入。例如,當我們修改了/etc/profile檔案,並想讓它立刻生效,而不用重新登入,就可以使用source命令,如source /etc/profile。


source命令(從 C Shell 而來)是bash shell的內建命令;點命令(.),就是個點符號(從Bourne Shell而來)是source的另一名稱。這從用法中也能看出來。


 


source filepath 與 sh filepath 、./filepath的區別:


    當shell指令碼具有可執行許可權時,用sh filepath與./filepath是沒有區別的。./filepath是因為當前目錄沒有在PATH中,所有"."是用來表示當前目錄的。


    sh filepath 會重新建立一個子shell,在子shell中執行腳本里面的語句,該子shell繼承父shell的環境變數,但子shell是新建的,其改變的變數不會被帶回父shell,除非使用export。


    source filename其實只是簡單地讀取腳本里面的語句依次在當前shell裡面執行,沒有建立新的子shell。那麼腳本里面所有新建、改變變數的語句都會儲存在當前shell裡面。


 


舉例說明:


    新建一個test.sh指令碼,內容為:A=1;


    修改其可執行許可權:chmod +x test.sh;


    執行sh test.sh後,echo $A,顯示為空,因為A=1並未傳回給當前shell;


    執行./test.sh後,也是一樣的效果;


    執行source test.sh 或者 . test.sh,然後echo $A,則會顯示1,說明A=1的變數在當前shell中;




Linux中exec命令相關:




exec和source都屬於bash內部命令(builtins commands),在bash下輸入man exec或man source可以檢視所有的內部命令資訊。
  bash shell的命令分為兩類:外部命令和內部命令。外部命令是通過系統呼叫或獨立的程式實現的,如sed、awk等等。內部


命令是由特殊的檔案格式(.def)所實現,如cd、history、exec等等。


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


  fork是linux的系統呼叫,用來建立子程序(child process)。子程序是父程序(parent process)的一個副本,從父程序那裡


獲得一定的資源分配以及繼承父程序的環境。子程序與父程序唯一不同的地方在於pid(process id)。


  環境變數(傳給子程序的變數,遺傳性是本地變數和環境變數的根本區別)只能單向從父程序傳給子程序。不管子程序的環境


變數如何變化,都不會影響父程序的環境變數。


  shell script:


  有兩種方法執行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)。


  exec:


  在bash下輸入man exec,找到exec命令解釋處,可以看到有”No new process is created.”這樣的解釋,這就是說exec命


令不產生新的子程序。那麼exec與source的區別是什麼呢?


  exec命令在執行時會把當前的shell process關閉,然後換到後面的命令繼續執行。


 


系統呼叫exec是以新的程序去代替原來的程序,但程序的PID保持不變。因此,可以這樣認為,exec系統呼叫並沒有建立新的


程序,只是替換了原來程序上下文的內容。原程序的程式碼段,資料段,堆疊段被新的程序所代替。


  一個程序主要包括以下幾個方面的內容:


  (1)一個可以執行的程式


  (2) 與程序相關聯的全部資料(包括變數,記憶體,緩衝區)


  (3)程式上下文(程式計數器PC,儲存程式執行的位置)