• linux之编写命令解释器


           一直在用命令解释器,但是对其中涉及的过程还不是很清楚,偶然看了Understanding Unix/Linux Programming一书,对其原理有所了解,记录学习过程。

    命令解释器主要干了这么三件事:

          1.接收用户输入命令

          2.创建一个子线程执行用户输入的命令

         3.父线程等待子线程执行完毕,继续接受用户命令

    下面是一个模拟命令解释器的过程,详情参见下面代码注释:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <signal.h>
    
    
    #define MAXVARS 10  //用于接受参数的个数
    #define ARGLEN 10  //用于接受一个参数所包含的字符个数
    
    
    
    void execute(char *arglist[])  //用于执行命令的函数
    {	
    	int i,pid,exitstatus;
    /*	for(i=0;arglist[i]!=NULL;i++)
    	{
    		printf("%s
    ",arglist[i]);
    	}
    */      
    	pid=fork(); //在父线程中产生一个子进程 并将子线程的线程id返回给父线程的pid变量
    	switch(pid) //根据pid来判断 是执行父线程代码 还是子线程的代码  
            //因为fork()函数给父线程返回子线程的线程id 给自己返回0
    	{
    		case -1:  //表示fork创建子线程失败
    			perror("fork faield");
    			exit(1); //结束父线程
    		case 0:  //表示成功创建子线程 并且在子线程中执行输入相关的命令
    			sleep(3); //子线程休眠3s中
    			printf("child sleep 3 seconds over.
    ");
    			execvp(arglist[0],arglist); //在PATH的环境变量里找到arglist[0]的命令 并执行
    			perror("execvp failed"); //如果上面的execvp正常执行的话 下面两句都不会执行 因为execvp会用arglist[0]命令的代码段和数据段替换掉子线程中的代码段和数据段
    			exit(1);
    		default:  //在父线程中所作的操作 使用wait等待子线程的执行完成 并带回子线程中所传递回来的值的地址给exitstatus变量 而wait函数返回子线程的进程id
    			while(wait(&exitstatus)!=pid); //判断子线程是否执行完毕
    			printf("child exit with status %d,%d
    ",exitstatus>>8,exitstatus&0xff);
    	}
    //	execvp(arglist[0],arglist);
    //	printf("end and error.
    ");
    //	exit(1);
    }
    
    char *make(char *buf)  //用于存储用户输入的参数
    {
    	char *cp;
    	buf[strlen(buf)-1]='';
    	cp=malloc(strlen(buf));
    	strcpy(cp,buf);
    	return cp;
    }
    
    
    int main(void)
    {
    	char *arglist[MAXVARS]; //用于接受用户输入的参数
    	int numargs; //用于记录用户输入了几个参数
    	char argbuf[ARGLEN]; //用于存储用户每一次输入的参数
    //	void execute(char *arglist[]);
    //	signal(SIGQUIT,SIG_IGN);
    	numargs=0;
    	while(numargs<MAXVARS) //不断的读取用户输入的命令并执行
    	{
    		printf("arg[%d]=",numargs); //显示提示信息
    		if(fgets(argbuf,ARGLEN,stdin)&&*argbuf!='
    ') //获取输入的命令 当输入为回车时 执行命令
    		{
    			arglist[numargs++]=make(argbuf);
    		}
    		else{
    			if(numargs>0)
    				arglist[numargs]=NULL; //参数列表的最后一个参数必须为(char *)NULL
    				execute(arglist); //执行参数
    				numargs=0;
    			}
    	}
    	return 0;
    }
    


     

    2.使用 gcc execvpfromstdin2.c -o efs

    3.运行 ./efs  如下

    对于上面的模拟过程,比较重要的就是这几个函数fork,execvp,exit,wait函数

         fork函数-----复制父进程的代码和数据,还有父进程所执行的位置(与父进程拥有相同的数据副本),并且返回两个值,一个值给父进程(即子线程的线程id),一个值给自己(为0),所以可通过fork的返回值来进行判断是位于子线程还是父线程

        execvp----使用一个新进程映像来替换当前进程映像(当前进程的代码和数据都将会被新进程替换)

        exit----结束进程,会关闭进程打开的文件,释放掉使用的内存,等等

        wait----会阻塞父线程,等待子线程执行完毕,并带回子线程的返回值.返回值为一个16位的数字,高8位为exit返回的数字.

     下面还有一个fork、execlp、wait函数使用的小例子:

    #include <stdio.h>
    #include <unistd.h>
    
    #define LEN 10
    
    main()
    {
    	char command[LEN];
    	int pid;
    	int status;
    	if(fork()==0)
    	{
    	 printf("this is a child process.pid=%d
    ",getpid());
    	execlp("ls","ls","-al","/etc/passwd",NULL);
    	perror("execlp error.");
    	}else{
    		sleep(1);
    		printf("this is parent process.pid=%d
    ",getpid());
    		printf("wait for child process.
    ");
    		pid=wait(&status);
    		printf("child process coming,pid=%d,status=%d
    ",pid,status);
    	}
    
    }
    

    运行结果如下:


  • 相关阅读:
    如何培养编程所需要的逻辑思维?
    CSS教程
    Android中Service(服务)详解
    Tomcat热部署的实现原理
    Java多线程和线程池(转)
    导出Excel表格
    各种时间格式化的转化
    上传多媒体文件到微信公众平台
    发起https请求并获取结果
    Java 将字节转换为十六进制字符串
  • 原文地址:https://www.cnblogs.com/liangxinzhi/p/4275606.html
Copyright © 2020-2023  润新知