目的:设计一个外壳接口,可以用来接受用户的命令,在一个单独的进程中执行用户命令。
外壳接口:为用户提供提示符,便于下一个命令的输入。
实现过程:父进程读取用户命令行的输入,然后创建一个单独的子进程来完成这个命令。
外壳基本轮廓:以main()函数提供osh>命令符为例:
#include <stdio.h>
#include <unistd.h>
int main(){
char *args[MAX_LINE/2 + 1];
int should_run = 1;
while(should_run){
printf("osh>");
fflush(stdout);
}
return 0;
}
fork()与exec的使用和区别:
系统调用fork():创建子进程,父进程和子进程之间共享代码段(建立相同的程序副本),仅通过复制指令、用户数据和系统数据段来创建从现存进程克隆的新进程,该新进程不是从程序初始化得来的,所以旧进程和新进程执行同样的指令。
系统调用exec():是以新的进程去代替原来的进程,但进程的PID保持不变。也就是exec系统调用并没有创建新的进程,只是替换了原来进程上下文的内容。原进程的代码段,数据段,堆栈段被新的进程所代替。
一般使用方法为:先调用fork(),再使用exec()来达到提高效率的目的。
exit():终止进程,如写如exit(1)来结束进程。
系统调用wait():等待子进程的终止。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <pwd.h>
#define MAX_LINE &
int main(){
char *args[MAX_LINE/2 + 1];
int should_run = 1;
while(should_run){
printf("osh>"); //设置提示符为‘osh>‘
fflush(stdout);
char c;
int i = 0;
do{
char *s = (char*)malloc( 128);
scanf("%s",s);
c = getchar();
args[i++] = s;
if(strcmp(args[0],"exit") == 0){should_run = 0;}//用户在提示符后面输入exit后,should_run为0并且终止;
if(strcmp(args[i-1],"&") == 0){i--;} //输入& 显示waitpid:success
}while(c == ' ');
args[i] = NULL;
pid_t id=fork(); //创建子进程,父进程和子进程之间共享代码段(建立相同的程序副本)
if (id < 0){
perror("fork"); //抛出异常
}
if(id == 0) {
execvp(args[0],args); //exec系列的一种,用于运行新程序
exit(1); //调用exit()来终止程序
}
else{
int status = 0;
pid_t ret = waitpid(id,&status,0);//等待子进程结束
if(ret > 0 && WIFEXITED(status))
{}
else{perror("waitpid");}
}
}
return 0;
}