zoukankan      html  css  js  c++  java
  • 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);
    	}
    
    }
    

    运行结果如下:


  • 相关阅读:
    LeetCode Single Number
    Leetcode Populating Next Right Pointers in Each Node
    LeetCode Permutations
    Leetcode Sum Root to Leaf Numbers
    LeetCode Candy
    LeetCode Sort List
    LeetCode Remove Duplicates from Sorted List II
    LeetCode Remove Duplicates from Sorted List
    spring MVC HandlerInterceptorAdapter
    yum
  • 原文地址:https://www.cnblogs.com/liangxinzhi/p/4275606.html
Copyright © 2011-2022 走看看