Linux C编程--进程介绍7--综合应用实例

时间:2022-05-12 14:54:58

第一个实例重点说明fork和exec系统函数

该实例是一个交互式命令处理程序,它能完成Linux系统标准Shell的小部分功能,具体功能如下所述:

1.提交命令的参数最多为8个

2.可前,后台执行

3.一命令行中可同时拥有多个命令,彼此之间用分号隔开


实现程序的主流程如下:

for(;;)

{

output("mini_SH-->");

readcmd();

docommand();

}


下面给出源代码:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

#define MAXARG 10
#define LINSIZ 80
#define CMDSIZ 8

extern char **environ;
char *quit="quit.quit";
char cmdbuf[CMDSIZ][LINSIZ];
int cmdflag[CMDSIZ];

int main()
{
	int i;
	for( ; ;)
	{
		printf("mini_SH-->");
		for(i=7;i>=0;i--)
		{
			cmdflag[i]=0;			/* */
			cmdbuf[i][0]='\0';
		}
		if(i=readcmd())				/* */
			docommand(i);			/* */
		else
			printf("read command failed, try again!!!\n");
	}
}

readcmd()
{
	char c,*p;
	int i=0;
	p=cmdbuf[0];
	while((c=getchar())!='\n')
	{
		if(c==';')
		{
			*p='\0';
			if(++i==6)
				return(++i);
			p=cmdbuf[i];
		}
		else if(c=='&')
		{
			cmdflag[i]=1;
		}
		else
			*p++=c;
	}
	*p='\0';
	return(++i);
}

docommand(int i)
{
	int j, stat, pid;
	char *argl[MAXARG], args[LINSIZ];
	char c, *argsp, **arglp, *p;

	for(j=0;j<i;j++)
	{
		arglp=argl;
		argsp=args;
		p=cmdbuf[j];
		while((c=*p++)!='\0')
		{
			while(c==' '|| c=='\t')
				c=*p++;
			if(c=='\0')
			{
				*argsp++='\0';
					break;
			}
			*arglp++=argsp;
			while(c!=' '&&c!='\t'&&c!='\0')
			{
				*argsp++=c;
				c=*p;
				if(c)  p++;
			}
			*argsp++='\0';
		}
		*arglp=(char *)0;
		if(strcmp(argl[0],quit)==0)
		{
			 printf("Bye Bye!\n");
			exit(0);
		}
		if((pid=fork())==0)
		{
			if(cmdflag[j]) setpgrp();
			execve(argl[0],argl,environ);
			printf("Returned from execve: %s\n",cmdbuf[i]);
			exit(10);
		}
		else
		{
			if(! cmdflag[j])
				while(wait(&stat)!=pid);

		}
	}

}

程序代码说明:

(1) 数据结构说明。该mini_SH定义了每条命令所能使用的最大参数个数为MAXARG,定义为10。每条命令的字符缓存数组由LINSIZ决定,最大为80,一次提交的命令个数由CMDSIZ决定,最多8个。字符指针quit存放退出命令字符串,它已经赋值为quit.quit,二维数组cmdbuf存放标准输入读到的字符串,而数组cmdflag决定该命令以何种方式执行,0为前台,1为后台。

(2)main函数。按主流程的设计思想实现,在无限循环for中,首先打印命令接收提示符mini_SH-->,将用户输入的命令字符串,通过函数readcmd得到并存储在cmdbuf二维数组中,readcmd返回一次提交的用分号隔开的命令个数。而函数docommand执行存放在cmdbuf中的命令。

(3)readcmd函数。将用户从标准输入提交的一行命令,按分号为界,分别存放命令缓冲区cmdbuf中,如果命令字符中有“&”符,将命令标志数组cmdflag的相应位置为1,每次提交命令时,该数组字段被清为0,并返回提交的命令个数。

(4)docommand函数。在for循环中,每次执行一条命令。用户提交的命令按顺序存放在数组cmdbuf中,while循环将命令执行的参数以空格或制表符为分界线,将字符型的指针数组argl分别指向相应的字符串,argl[0]指向该命令字符串,arg[1]是该命令的第一个参数,以此类推,最后一个参数为空指针。对于每一个参数增加一个空字符”\0“。如果命令字符串为定义的退出该命令字符串quit.quit,则调用exit系统函数退出执行,否则,调用fork生成子进程。如果设置后台标志位,则重新设置进程组号,使用带环境变量的系统调用execve执行用户提交用户执行的命令,如该命令以后台方式执行,则父进程不等待该命令执行完后就可执行新的命令。否则,父进程使用wait函数等待子进程执行暂停或终止。


该程序是一个完整的程序,编译后生成mini_sh命令,一下是在mini_sh命令控制下,用户提交命令的执行情况:

$ ./mini_sh

mini_SH-->/bin/date

2011年12月05日 星期一 23:37:19 PST

mini_SH-->/bin/who

Returned from execve:

mini_SH-->/bin/pwd;/bin/date

/home/lxy/test1/BruceZhang

2011年12月05日 星期一 23:37:19 PST

mini_SH-->quit.quit

Bye Bye!