1. 程式人生 > >UNIX環境高階程式設計的學習(二)

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函式用於阻塞自己,及時銷燬已經變成殭屍程序的子程序。