UNIX環境高階程式設計的學習(二)
UNIX系統程序控制程式說明
該程式從標準輸入讀取命令,然後執行這些命令,程式涉及到的函式主要用法包括:
- fgets的用法
- execlp的用法
- waitpid的用法
程式如下:
#include "apue.h" #include <sys/wait.h> int main(void) { char buf[MAXLINE]; pid_t pid; int status; printf("%% "); while(fgets(buf,MAXLINE,stdin)!=NULL){ if(buf[strlen(buf)-1]=='\n') buf[strlen(buf)-1]=0; if((pid=fork())<0){ err_sys("fork error"); }else if(pid==0){ /*child*/ execlp(buf,buf,(char*)0); err_ret("couldn't execute:%s",buf); exit(127); } /*parent*/ if((pid=waitpid(pid,&status,0))<0) err_sys("waitpid error"); printf("%% "); } exit(0); }
- fgets的用法
fgets(buf,MAXLINE,stdin);
從標準輸入中讀取資料,每次讀取一行,讀取的資料儲存在buf指向的字元陣列中,每次最多讀取bufsize-1個字元,第bufsize個字元賦’\0’;如果檔案中的字元不足bufsize-1個字元則讀完該行結束,在這裡MAXLINE應該是一個比較大的數,這樣可以確保讀完一行。 - execlp的用法
execlp(buf,buf,(char)0);*
1.這個函式用來替換程序映像,在程序的建立上Unix採用了一個獨特的方法,它將程序建立與載入一個新程序映象分離。這樣的好處是有更多的餘地對兩種操作進行管理。 當我們建立了一個程序之後,通常將子程序替換成新的程序映象,這可以用exec系列的函式來進行。當然,exec系列的函式也可以將當前程序替換掉。 例如:在shell命令列執行ps命令,實際上是shell程序呼叫fork複製一個新的子程序,再利用exec系統呼叫將新產生的子程序完全替換成ps程序。
2.實際上execlp()函式底層是通過execve系統呼叫實現:
#include <unistd.h>
int execve(const char *filename, char *const argv[],char *const envp[]);
DESCRIPTION:
execve() executes the program pointed to by filename. filename must be either a binary executable, or a script starting with a line of the form
第一個引數用來指定啟動程式的名稱包括路徑名,如“/bin/pwd";
第二個引數用arg引數表示啟動程式所帶的引數,一般第一個引數為要執行命令名,不是帶路徑且arg必須以NULL結束
3.execlp()函式的特殊之處:
execlp第一個引數path不用輸入完整路徑,只有給出命令名即可,它會在環境變數PATH當中查詢命令,也就是說可以不用再前面加斜線’/’;
- waitpid的用法
waitpid系統呼叫在Linux函式庫中的原型是:
#include <sys/types.h> /* 提供型別pid_t的定義 */
#include <sys/wait.h>
pid_t waitpid(pid_t pid,int *status,int options)
1.程序一旦呼叫了wait,就立即阻塞自己,由wait自動分析是否當前程序的某個子程序已經退出,如果讓它找到了這樣一個已經變成殭屍的子程序,wait就會收集這個子程序的資訊,並把它徹底銷燬後返回;如果沒有找到這樣一個子程序,wait就會一直阻塞在這裡,直到有一個出現為止。
引數status用來儲存被收集程序退出時的一些狀態,它是一個指向int型別的指標。但如果我們對這個子程序是如何死掉的毫不在意,只想把這個殭屍程序消滅掉,(事實上絕大多數情況下,我們都會這樣想),我們就可以設定這個引數為NULL,就象下面這樣:pid = wait(NULL);如果成功,wait會返回被收集的子程序的程序ID,如果呼叫程序沒有子程序,呼叫就會失敗,此時wait返回-1,同時errno被置為ECHILD。
2.pid:從引數的名字pid和型別pid_t中就可以看出,這裡需要的是一個程序ID。pid>0時,只等待程序ID等於pid的子程序,不管其它已經有多少子程序執行結束退出了,只要指定的子程序還沒有結束,waitpid就會一直等下去。
3.waitpid的返回值比wait稍微複雜一些,一共有3種情況:
1、當正常返回的時候,waitpid返回收集到的子程序的程序ID;
2、如果設定了選項WNOHANG,而呼叫中waitpid發現沒有已退出的子程序可收集,則返回0;
3、如果呼叫中出錯,則返回-1,這時errno會被設定成相應的值以指示錯誤所在;
綜上:
首先列印一個提示符’%’,但是要寫兩個’%%‘才能輸出一個’%‘;然後輸入一個命令,接收到命令之後,建立一個子程序,子程序建立成功(即pid=0),通過ececlp函式,將子程序替換為剛剛接收到的輸入命令,並執行該命令,輸出執行後的結果,waitpid函式用於阻塞自己,及時銷燬已經變成殭屍程序的子程序。