本實(shí)驗(yàn)是要求在linux環(huán)境下測(cè)試fork()和exec()嗦玖,并建立一個(gè)簡(jiǎn)單的shell(帶cd宇挫、env翠储、echo援所、help、jobs滔岳、quit命令)
-
fork()
這一節(jié)沒(méi)啥難度,主要是測(cè)試當(dāng)前l(fā)inux環(huán)境下gcc是否能編譯成功
清單 2-1 創(chuàng)建進(jìn)程
#include <stdio.h> //此處指導(dǎo)書上沒(méi)有
int main (){
int x;
while((x=fork())==-1);
if (x==0)
printf("a");
else
printf("b");
printf("c");
}
這里出現(xiàn)了很奇妙的問(wèn)題,指導(dǎo)書上沒(méi)有使用stdio頭文件奏赘,不過(guò)顯然這樣編譯不會(huì)通過(guò)。但是加上了以后又出現(xiàn)了一個(gè)坑梁只,實(shí)驗(yàn)室里的linux沒(méi)有安裝gcc的包依賴。此處需要我們重裝個(gè)gcc
$ sudo apt-get install build-essential //此處也許會(huì)失敗构舟,提示缺少幾個(gè)依賴,那就安裝相應(yīng)的包
$ sudo apt-get install g++ //上一步如果不行就運(yùn)行這個(gè)再運(yùn)行上一條
linux下怎么build .c文件也留檔一下吧
$ gcc -o hello hello.c // 第一個(gè)為生成的文件名努咐,第二個(gè)為.c文件
-
exec()
這真是一個(gè)騷操作∫粑澹可以直接用新的進(jìn)程映象置換當(dāng)前的進(jìn)程映象躺涝,留檔函數(shù)原型
exec 系列有 6 個(gè)函數(shù)坚嗜,原型如下:
extern char **environ;
int execl( const char *path, const char *arg, ...);
int execlp( const char *file, const char *arg, ...);
int execle( const char *path, const char *arg , ..., char * const envp[]);
int execv( const char *path, char *const argv[]);
int execve (const char *filename, char *const argv [], char *const envp[]);
int execvp( const char *file, char *const argv[]);
exec 系列函數(shù)用新的進(jìn)程映象置換當(dāng)前的進(jìn)程映象.這些函數(shù)的第一個(gè)參數(shù)是待執(zhí)行程序的路
徑名(文件名)。這些函數(shù)調(diào)用成功后不會(huì)返回,其進(jìn)程的正文(text),數(shù)據(jù)(data)和棧(stack)段被待執(zhí)行
程序程序覆蓋碟绑。但是進(jìn)程的 PID 和所有打開(kāi)的文件描述符沒(méi)有改變,同時(shí)懸掛信號(hào)被清除,信號(hào)重
置為缺省行為凯肋。
在函數(shù) execl,execlp,和 execle 中, const char *arg 以及省略號(hào)代表的參數(shù)可被視為 arg0,
arg1, ...,argn。它們合起來(lái)描述了指向 NULL 結(jié)尾的字符串的指針列表苗桂,即執(zhí)行程序的參數(shù)列表煤伟。作
為約定,第一個(gè) arg 參數(shù)應(yīng)該指向執(zhí)行程序名自身,參數(shù)列表必須用 NULL 指針結(jié)束。
execv 和 execvp 函數(shù)提供指向 NULL 結(jié)尾的字符串的指針數(shù)組作為新程序的參數(shù)列表放案。作為約
定掸冤,指針數(shù)組中第一個(gè)元素應(yīng)該指向執(zhí)行程序名自身憨攒。指針數(shù)組必須用 NULL 指針結(jié)束。
execle 函數(shù)同時(shí)說(shuō)明了執(zhí)行進(jìn)程的環(huán)境(environment),它在 NULL 指針后面要求一個(gè)附加參
數(shù),NULL 指針用于結(jié)束參數(shù)列表,或者說(shuō),argv 數(shù)組妹蔽。這個(gè)附加參數(shù)是指向 NULL 結(jié)尾的字符串的指
針數(shù)組,它必須用 NULL 指針結(jié)束。其它函數(shù)從當(dāng)前進(jìn)程的 environ 外部變量中獲取新進(jìn)程的環(huán)境元镀。
execlp和execvp可根據(jù)path搜索合適的程序運(yùn)行,其它則需要給出程序全路徑萎坷。
execve()類似 execv()凹联,但是加上了環(huán)境的處理沐兰。
在把此處的示例程序解釋一下吧:
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int main(){
pid_t pid;
/* fork a child process */
pid = fork();
if (pid < 0){
/* error occurred */
fprintf(stderr, "Fork Failed");
return 1;
}
else if (pid == 0){
/* 子進(jìn)程 */
execlp("/bin/ls","ls",NULL);
}
else { /* 父進(jìn)程 */
/ * 父進(jìn)程將一直等待哆档,直到子進(jìn)程運(yùn)行完畢*/
wait(NULL);
printf("Child Complete");
}
return 0;
}
我的理解是這份代碼的意思應(yīng)該是,創(chuàng)建一個(gè)進(jìn)程住闯,如果該進(jìn)程的pid<0(當(dāng)然創(chuàng)建fork成功會(huì)返回大于0的數(shù))提示fork失敗瓜浸。然后再使用execlp調(diào)用系統(tǒng)中的ls命令,運(yùn)行結(jié)果圖
-
簡(jiǎn)單的shell
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
char op[256];
char arg[256];
char str[1024];
int main()
{
pid_t CurSon;
while(1){
scanf("%s", op);
if(strcmp(op, "quit") == 0 || strcmp(op, "exit") == 0 || strcmp(op, "bye") == 0){
printf("\nQuiting...Bye~");
return 0;
}else if(strcmp(op, "help") == 0){
printf("It's a fake shell~\n");
}else if(strcmp(op, "cd") == 0){
scanf("%s", arg);
sprintf(str, "cd %s", arg);
system(str);
}else if(strcmp(op, "environ") == 0){
system("env");
}else if(strcmp(op, "echo") == 0){
scanf("%s", arg);
sprintf(str, "echo %s", arg);
system(str);
}else if(strcmp(op, "jobs") == 0){
system("ps");
}else{
fgets(arg, 256, stdin);
sprintf(str, "%s %s", op, arg);
while((CurSon = fork()) < 0);
if(CurSon == 0){
system(str);
return 0;
}else{
wait(NULL);
printf("%s\n", str);
printf("Complete...\n");
}
}
}
return 0;
}