版权声明: https://blog.csdn.net/zl6481033/article/details/86540520
1、利用fork和execve运行程序
像Unix shell和Web服务器这样的程序使用了大量得fork和execve函数,shell是一个交互型程序,代表用户运行其他程序。shell执行一系列的读/求值步骤,然后终止,读步骤读取来自用户的一个命令行,求值步骤解析命令行,并代表用户运行程序。
主程序主要是等待用户在stdin输入命令行,并且对命令行求值。eval函数对shell命令求值。parseline函数对命令行参数进行解析,builtin_command函数,检查命令行参数是内置指令还是一个可执行文件。
#include"csapp.h"
#define MAXARGS 128
//函数声明
void eval(char* cmdline);
int parseline(char* buf,char **argv);
int builtin_command(char **argv);
int main()
{
char cmdline[MAXLINE];
while(1)
{
//提示输入命令
printf(">");
Fgets(cmdline,MAXLINE,stdin);
if(feof(stdin))
exit(0);
//对命令求值
eval(cmdline);
}
}
void eval(char *cmdline)
{
char *argv[MAXARGS];
char buf[MAXLINE];
int bg;
pid_t pid;
strcpy(buf,cmdline);
//解析以空格分隔的命令行参数
bg=parseline(buf,argv);
if(argv[0]==NULL)
return ;
//如果是内置指令则不会进入,如果不是,说明是一个可执行文件,进入之后,创建子进程并执行。
if(!builtin_command(argv)){
if((pid=Fork()==0)){
if(execve(argv[0],argv,environ)<0){
printf("%s,command not found.\n",argv[0]);
exit(0);
}
}
if(!bg){
int status;
if(waitpid(pid,&status,0)<0)
unix_error("waitfg :waitpid error");
}
else
printf("%d %s",pid,cmdline);
}
return ;
}
//检查第一个命令行参数是否一个内置的shell命令若是则解释返回1,否则返回0
int builtin_command(char **argv)
{
//判断是不是内置指令
if(!strcmp(argv[0],"quit"))
exit(0);
if(!strcmp(argv[0],"&"))
return 1;
return 0;
}
//解析shell的一行输入行,解析以空格分隔的命令行参数,并最终传递给argv向量。第一个参数
//要么是一个内置指令,要么是一个可执行文件,会在一个新的子进程执行该程序。如果最后一个参数是
//&字符,那么该函数返回1表示在后台执行这个程序,否则返回0在前台执行。
int parseline(char *buf,char **argv)
{
char *delim;
int argc;
int bg;
buf[strlen(buf)-1]=' ';
while(*buf&&(*buf==' '))
buf++;
argc=0;
while((delim=strchr(buf,' '))){
argv[argc++]=buf;
*delim='\0';
buf=delim+1;
while(*buf&&(*buf==' '))
buf++;
}
argv[argc]=NULL;
if(argc==0)
return 1;
if((bg=(*argv[argc-1]=='&'))!=0)
argv[--argc]=NULL;
return bg;
}
2、执行结果
3、缺陷
这个简单的shell程序是有缺陷的,因为它并不回收后台子进程,修改这个缺陷需要使用信号。