exec執(zhí)行普通文件和解釋器文件的區(qū)別
先解釋兩個概念;解釋器文件和解釋器。
l 解釋器文件:一種文本文件,開頭通常是:#! pathname [option-argument];比較常見的是#! /bin/bash,shell腳本和python腳本都屬于解釋器文件。
l 解釋器:解釋器文件第一行中pathname指定的程序,如bash。
3.1 解釋器文件的執(zhí)行
當(dāng)執(zhí)行(exec)解釋器文件時,exec系統(tǒng)調(diào)用會識別這種文件,內(nèi)核使調(diào)用exec函數(shù)的進(jìn)程實(shí)際執(zhí)行的并不是該解釋器文件,而是pathname指定的解釋器。
我們可以自己寫一個解釋器,如之前所寫的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/。
下面我們在自己寫一個”解釋器文件”——test:
l test
#!/mnt/hgfs/VWShared/foo
3.1.1 通過命令行執(zhí)行解釋器文件
直接在命令行中鍵入:”./test”,運(yùn)行test,效果如圖5。
圖5
將test內(nèi)容修改為:#!/mnt/hgfs/VWShared/foo argA argB,再次在命令行運(yùn)行test,效果如圖6。
圖6
通過這兩個例子,可以看出命令行運(yùn)行時當(dāng)執(zhí)行文件是”解釋器文件”時,參數(shù)是如何傳遞給解釋器的:
(1) 通過執(zhí)行”解釋器文件”執(zhí)行解釋器,傳遞給解釋器的第一個參數(shù)是解釋器文件的pathname,即解釋器的路徑。
(2) “解釋器文件”中pathname后的可選參數(shù)(這里的argA,argB)如果存在的話會一起作為第二個參數(shù)傳遞給解釋器。
(3) “解釋器文件”名稱會作為下一個參數(shù)傳遞給解釋器。
3.1.2 通過execl執(zhí)行解釋器文件
接下來通過execl執(zhí)行解釋器文件test,修改main中的exec語句如下:
execl(/mnt/hgfs/VWShared/test,arg1,”arg2”,(char*)0));然后執(zhí)行main,效果如圖7。
圖7
從這個例子可以了解當(dāng)執(zhí)行文件是解釋器文件時,內(nèi)核如何處理exec函數(shù)的參數(shù)及解釋器文件第一行的可選參數(shù)。我們知道執(zhí)行解釋器文件實(shí)際是執(zhí)行解釋器,由解釋器去讀取解釋器文件中的語句執(zhí)行,而第一行的pathname以#開頭在執(zhí)行時會被當(dāng)做注釋忽略。下面就讓我們分析一下最終傳入解釋器foo的參數(shù)都是什么。
(1) argv[0]是該解釋器文件的pathname;
(2) argv[1]是該解釋文件中的可選參數(shù);
(3) argv[2]是解釋器文件本身名字;
(4) argv[3]是execl出入的第二個參數(shù)(第一個參數(shù)是arg1)。
那么問題出現(xiàn)了,我們傳入execl的arg1去哪里了呢?其實(shí)這就是exec執(zhí)行”解釋器文件”和執(zhí)行一般程序的不同之處:在執(zhí)行一般程序時,execl(const char* pathname,const char* arg0,...,(char*)0)中的arg0會被當(dāng)做執(zhí)行程序(pathname)的第一個參數(shù)argv[0],而在執(zhí)行解釋器文件時,內(nèi)核取execl調(diào)用中的pathname而非第一個參數(shù)(arg0)作為第一個參數(shù)傳遞給解釋器,因?yàn)橐话愣?,第一個參數(shù)arg0通常是解釋器文件的名字,而pathname包含了比arg0更多的信息(解釋器文件的完整路徑)。所以當(dāng)execl執(zhí)行解釋器文件時第一個參數(shù)arg0是無效的。
為了說明這個問題,我們再舉一個例子,編寫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一樣同樣是打印每個命令行參數(shù)。我們分別將main中的execl語句改為:
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))結(jié)果
圖9.execl(/mnt/hgfs/VWShared/pyth.py,arg1,arg2,(char*)0))結(jié)果
可以看出execl對于執(zhí)行普通文件和解釋器文件選取第一個參數(shù)是不同的。
3.2 execl執(zhí)行解釋器文件和命令行執(zhí)行解釋器文件的不同
我們上面已經(jīng)看到execl(/mnt/hgfs/VWShared/pyth.py,arg1,arg2,(char*)0))的結(jié)果(圖9),下面我們試一下命令行方式:pyth.py arg1 arg2,結(jié)果圖10:
圖10
可以看到結(jié)果和通過execl執(zhí)行是有區(qū)別的,通過命令行執(zhí)行解釋器文件就像通過命令行執(zhí)行普通程序一樣,程序名稱作為第一個參數(shù),命令行后面依次作為后續(xù)參數(shù)。正因?yàn)閷τ诮忉屍魑募膃xecl方式和命令行方式執(zhí)行時選取第一個參數(shù)的方式不同,所以對于解釋器文件a.py:
評論