shell是什么?
维基百科:Unix shell也叫做命令行界面,它是Unix操作系统下传统的用户和计算机的交互界面。用户直接输入命令来执行各种各样的任务。
现在的shell不止这些功能,不过,这些与本文无关。
shell中命令的执行过程?
启动shell,本身就是创建一个进程。在shell中运行命令的时候,shell进程会以自己为模板,创建(fork)一个新的进程。这个新建的进程对shell中输入的命令进行处理,处理完之后新进程结束自己的生命,等待shell进程进行回收。具体来说,就是:
- shell进程调用fork()这一系统调用来创建了一个子进程。
- 父进程(也就是shell进程)调用wait()这一系统调用后进行等待,直到新建的子进程结束。
- 子进程调用exec()这一系统调用来执行shell中输入的命令,执行完成后,调用exit()这一系统调用来结束生命。
- 父进程的wait()回收信息,释放子进程的PCB,彻底销毁子进程。
shell是如何实现的?
下面是《Unix/Linux编程实践教程》中的代码。
#define MAXARGS 20
#define ARGLEN 100
main()
{
char *arglist[MAXARGS+1];
int numargs;
char argbuf[ARGLEN];
char *makestring();
numargs = 0;
while ( numargs < MAXARGS )
{
printf("Arg[%d]? ", numargs);
if ( fgets(argbuf, ARGLEN, stdin) && *argbuf != '\n' )
arglist[numargs++] = makestring(argbuf);
else
{
if ( numargs > 0 ){
arglist[numargs]=NULL;
execute( arglist );
numargs = 0;
}
}
}
return 0;
}
execute( char *arglist[] )
{
int pid,exitstatus;
pid = fork(); //在这里,shell就有了自己的分身,也就是子进程(这里可以看作内存中运行了2个相同的进程)。
switch( pid ){
case -1:
perror("fork failed");
exit(1);
case 0:
execvp(arglist[0], arglist); //如果PID是0,说明是子进程,运行新的命令(新的shell有了新的思想)。
perror("execvp failed");
exit(1);
default:
while( wait(&exitstatus) != pid )//父进程shell等待子进程结束,并获取信息。
;
printf("child exited with status %d,%d\n",
exitstatus>>8, exitstatus&0377);
}
}
char *makestring( char *buf )
{
char *cp, *malloc();
buf[strlen(buf)-1] = '\0';
cp = malloc( strlen(buf)+1 );
if ( cp == NULL ){
fprintf(stderr,"no memory\n");
exit(1);
}
strcpy(cp, buf);
return cp;
}
刚学习fork时候,一直把父子进程看作一个程序,只是在理论上知道fork是复制了一个自己,通过上面的程序终于对fork有了一个较为清晰的认识。就好比一个懒人自己总不想做事,想要学会分身术,让分身去做事。在linux中这个懒人就是init进程,它复制了很多自己来为它做事,这些孩子们遗传了它的个性,也喜欢复制自己去做事,这就是linux系统中的一个个进程。