exec執行普通文件和解釋器文件的區別
先解釋兩個(gè)概念;解釋器文件和解釋器。
l 解釋器文件:一種文本文件,開(kāi)頭通常是:#! pathname [option-argument];比較常見(jiàn)的是#! /bin/bash,shell腳本和python腳本都屬于解釋器文件。
l 解釋器:解釋器文件第一行中pathname指定的程序,如bash。
3.1 解釋器文件的執行
當執行(exec)解釋器文件時(shí),exec系統調用會(huì )識別這種文件,內核使調用exec函數的進(jìn)程實(shí)際執行的并不是該解釋器文件,而是pathname指定的解釋器。
我們可以自己寫(xiě)一個(gè)解釋器,如之前所寫(xiě)的foo.c:
l foo.c
#include
int
main(int argc,char* argv[])
{
int i;
for(i=0;i
printf(argv[%d]: %sn,i,argv[i]);
exit(0);
}
編譯成為foo然后保存在/mnt/hgfs/VWShared/。
下面我們在自己寫(xiě)一個(gè)”解釋器文件”——test:
l test
#!/mnt/hgfs/VWShared/foo
3.1.1 通過(guò)命令行執行解釋器文件
直接在命令行中鍵入:”./test”,運行test,效果如圖5。

圖5
將test內容修改為:#!/mnt/hgfs/VWShared/foo argA argB,再次在命令行運行test,效果如圖6。

圖6
通過(guò)這兩個(gè)例子,可以看出命令行運行時(shí)當執行文件是”解釋器文件”時(shí),參數是如何傳遞給解釋器的:
(1) 通過(guò)執行”解釋器文件”執行解釋器,傳遞給解釋器的第一個(gè)參數是解釋器文件的pathname,即解釋器的路徑。
(2) “解釋器文件”中pathname后的可選參數(這里的argA,argB)如果存在的話(huà)會(huì )一起作為第二個(gè)參數傳遞給解釋器。
(3) “解釋器文件”名稱(chēng)會(huì )作為下一個(gè)參數傳遞給解釋器。
3.1.2 通過(guò)execl執行解釋器文件
接下來(lái)通過(guò)execl執行解釋器文件test,修改main中的exec語(yǔ)句如下:
execl(/mnt/hgfs/VWShared/test,arg1,”arg2”,(char*)0));然后執行main,效果如圖7。

圖7
從這個(gè)例子可以了解當執行文件是解釋器文件時(shí),內核如何處理exec函數的參數及解釋器文件第一行的可選參數。我們知道執行解釋器文件實(shí)際是執行解釋器,由解釋器去讀取解釋器文件中的語(yǔ)句執行,而第一行的pathname以#開(kāi)頭在執行時(shí)會(huì )被當做注釋忽略。下面就讓我們分析一下最終傳入解釋器foo的參數都是什么。
(1) argv[0]是該解釋器文件的pathname;
(2) argv[1]是該解釋文件中的可選參數;
(3) argv[2]是解釋器文件本身名字;
(4) argv[3]是execl出入的第二個(gè)參數(第一個(gè)參數是arg1)。
那么問(wèn)題出現了,我們傳入execl的arg1去哪里了呢?其實(shí)這就是exec執行”解釋器文件”和執行一般程序的不同之處:在執行一般程序時(shí),execl(const char* pathname,const char* arg0,...,(char*)0)中的arg0會(huì )被當做執行程序(pathname)的第一個(gè)參數argv[0],而在執行解釋器文件時(shí),內核取execl調用中的pathname而非第一個(gè)參數(arg0)作為第一個(gè)參數傳遞給解釋器,因為一般而言,第一個(gè)參數arg0通常是解釋器文件的名字,而pathname包含了比arg0更多的信息(解釋器文件的完整路徑)。所以當execl執行解釋器文件時(shí)第一個(gè)參數arg0是無(wú)效的。
為了說(shuō)明這個(gè)問(wèn)題,我們再舉一個(gè)例子,編寫(xiě)python文件pyth.py如下:
l pyth.py:
#! /usr/bin/python
import sys
for i in range(0,len(sys.argv)):
print argv[%d]: %s%(i,sys.argv[i])
它的功能和foo一樣同樣是打印每個(gè)命令行參數。我們分別將main中的execl語(yǔ)句改為:
execl(/mnt/hgfs/VWShared/foo,arg1,arg2,(char*)0))和
execl(/mnt/hgfs/VWShared/pyth.py,arg1,arg2,(char*)0)),對比execl一般程序(foo)和解釋器文件(pyth.py)的效果如圖8、9。

圖8.execl(/mnt/hgfs/VWShared/foo,arg1,arg2,(char*)0))結果

圖9.execl(/mnt/hgfs/VWShared/pyth.py,arg1,arg2,(char*)0))結果
可以看出execl對于執行普通文件和解釋器文件選取第一個(gè)參數是不同的。
3.2 execl執行解釋器文件和命令行執行解釋器文件的不同
我們上面已經(jīng)看到execl(/mnt/hgfs/VWShared/pyth.py,arg1,arg2,(char*)0))的結果(圖9),下面我們試一下命令行方式:pyth.py arg1 arg2,結果圖10:

圖10
可以看到結果和通過(guò)execl執行是有區別的,通過(guò)命令行執行解釋器文件就像通過(guò)命令行執行普通程序一樣,程序名稱(chēng)作為第一個(gè)參數,命令行后面依次作為后續參數。正因為對于解釋器文件的execl方式和命令行方式執行時(shí)選取第一個(gè)參數的方式不同,所以對于解釋器文件a.py:
評論