简单shell命令行解释器的设计与实现

简单shell命令行解释器的设计与实现

思路&分析

1.背景知识
本实验要使用创建子进程的fork()函数,执行新的命令的exec ()系列函数,通常shell是等待子进程结束后再接受用户新的输入,这可以使用waitpid()函数。
2.设计步骤
提示:shell的主体就是反复下面的循环过程
while(1){
接收用户输入的命令行;
解析命令行;
if(用户命令为内部命令)
直接处理;
elseif(用户命令为外部命令)
创建子进程执行命令;
else
提示错误的命令;
}
3.根据设计步骤逐步完成各个命令

  1. 首先是接受键盘的输入数据,这里我们采用一个字符串数组,一个一个字符读入,赋值给该字符串数组。

  2. 解析命令行:将输入数据按照空格分开,第一个字符串为命令,之后几个为参数。

  3. 根据第一个字符串参数判断是什么命令。

  4. 若为echo,后面有数据则输出。

  5. 若为cd,则利用chdir()函数切换目录,然后通过自己写的pwd()函数获取当前目录输出。

  6. 若为help命令,直接输出相关内容。

  7. environ,则通过fork()创建子进程,利用函数exec()执行,env命令。

  8. jobs,自己写一个函数获取当前shell的进程名和进程ID,Linux下的当前正在运行的进程信息均存放在/proc目录下,有一系列以数字为名的子目录,每一个子目录对应一个进程,子目录名就是进程的pid。子目录下的status文件内容就是进程的基本信息,包括进程名、pid、ppid等。因此,若要扫描系统当前正在运行的所有进程,只需要遍历/proc目录下所有以数字为名的子目录下的status即可。据此,可得到获取当前系统所有进程快照、根据pid获得进程名和根据进程名获得pid的程序。该命令参照博客链接

  9. quit,bye,exit,直接用exit()即可。

结果

结果截图一:help,echo,cd,pwd
在这里插入图片描述
结果截图二:jobs,envirn,bye
在这里插入图片描述

代码(linux执行下)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pwd.h>
#include <dirent.h>

#define BUF_SIZE 1024
#define MAX_PROCESS_PATH 1024
#define PROC_NAME_FIELD ("name:")
#define PARENT_PID_FIELD ("ppid:")
#ifndef __cplusplus
typedef enum {false, true} bool;
#endif // __cplusplus

typedef struct __tagProcessEntry
{
   pid_t pid;
   pid_t ppid;
   char processName[MAX_PROCESS_PATH];
} ProcessEntry;

void string2lower(const char src[], char dest[])
{
   int length = strlen(src);
   int index;
   for(index = 0; index < length; index ++)
   {
      dest[index] = ((src[index] >= 'A') && (src[index] <= 'Z')) ? src[index] + 0x20 : src[index];
   }
   dest[length] = '\0';
}

int createProcessSnapshot(ProcessEntry pes[], int maxCount)
{
   int processCount = 0;
   DIR *dir;
   struct dirent *dirEntry;
   FILE *fp;
   char filePath[MAX_PROCESS_PATH];
   char fieldName[32];
   char fieldValue[MAX_PROCESS_PATH];
   char buf[BUF_SIZE];

   dir = opendir("/proc");
   if (NULL != dir)
   {
      while((dirEntry = readdir(dir)) != NULL) //循环读取路径下的每一个文件/文件夹
      {
         //如果读取到的是"."或者".."则跳过,读取到的不是文件夹名字也跳过
         if ((strcmp(dirEntry->d_name, ".") == 0) || (strcmp(dirEntry->d_name, "..") == 0) || (DT_DIR != dirEntry->d_type))
         {
            continue;
         }

         sprintf(filePath, "/proc/%s/status", dirEntry->d_name); //生成要读取的文件的路径
         fp = fopen(filePath, "r");
         if (NULL != fp)
         {
            do {
               if (fgets(buf, BUF_SIZE - 1, fp) == NULL)
               {
                  break;
               }
               sscanf(buf, "%s %s", fieldName, fieldValue);
               string2lower(fieldName, fieldName);
               if (strcmp(fieldName, PROC_NAME_FIELD) == 0)
               {
                  strcpy(pes[processCount].processName, fieldValue);
               }
               else if (strcmp(fieldName, PARENT_PID_FIELD) == 0)
               {
                  pes[processCount].ppid = atoi(fieldValue);
               }
            } while(!feof(fp));
            fclose(fp);

            pes[processCount].pid = atoi(dirEntry->d_name);
            processCount ++;
            if (processCount >= maxCount)
            {
               break;
            }
         }
      }
      closedir(dir);
   }
   return processCount;
}

int getPidByName(const char *procName, pid_t pids[], int maxCount)
{
   DIR *dir;
   struct dirent *dirEntry;
   FILE *fp;
   char filePath[MAX_PROCESS_PATH];
   char currProcName[MAX_PROCESS_PATH];
   char buf[BUF_SIZE];
   int pidCount = 0;

   dir = opendir("/proc");
   if (NULL != dir)
   {
      while((dirEntry = readdir(dir)) != NULL) //循环读取路径下的每一个文件/文件夹
      {
         //如果读取到的是"."或者".."则跳过,读取到的不是文件夹名字也跳过
         if ((strcmp(dirEntry->d_name, ".") == 0) || (strcmp(dirEntry->d_name, "..") == 0) || (DT_DIR != dirEntry->d_type))
         {
            continue;
         }

         sprintf(filePath, "/proc/%s/status", dirEntry->d_name); //生成要读取的文件的路径
         fp = fopen(filePath, "r"); //打开进程描述文件
         if (NULL != fp)
         {
            if (fgets(buf, BUF_SIZE - 1, fp) == NULL)
            {
               fclose(fp);
               continue;
            }
            sscanf(buf, "%*s %s", currProcName);

            if (strcmp(procName, currProcName) == 0)
            {
               pids[pidCount] = atoi(dirEntry->d_name);
               pidCount ++;
               if (pidCount >= maxCount)
               {
                  break;
               }
            }
            fclose(fp);
         }
      }
      closedir(dir);
   }
   return pidCount;
}

bool getNameByPid(pid_t pid, char procName[])
{
   char pidPath[BUF_SIZE];
   char buf[BUF_SIZE];
   bool success = false;

   sprintf(pidPath, "/proc/%d/status", pid);
   FILE *fp = fopen(pidPath, "r");
   if (NULL != fp)
   {
      if (fgets(buf, BUF_SIZE - 1, fp) != NULL)
      {
         sscanf(buf, "%*s %s", procName);
         success = true;
      }
      else
      {
         success = false;
      }
      fclose(fp);
   }

   return success;
}
void print()
{
	struct passwd *usrname;
	usrname = getpwuid(getuid());
	char buf[256];
	memset(buf,0,sizeof(buf));
	printf("[my_shell:%s]",getcwd(buf,256));
	if(strcmp(usrname->pw_name,"root")==0)
		printf("#");
	else
		printf("$");
}

int shellJudgment(char *arglist[],int args_num)
{
    if(strcmp(arglist[0],"cd")==0||strcmp(arglist[0],"pwd")==0)
        return 1;//cd
    else if(strcmp(arglist[0],"help")==0&&(args_num==1))//help
        return 2;
    else if(strcmp(arglist[0],"environ")==0&&(args_num==1))//environ
        return 3;
    else if(strcmp(arglist[0],"echo")==0)//echo
        return 4;
    else if(strcmp(arglist[0],"jobs")==0)//jobs
        return 5;
    else if((strcmp(arglist[0],"quit")==0)||(strcmp(arglist[0],"exit")==0)||(strcmp(arglist[0],"bye")==0)&&(args_num==1))//bye
        return 6;
    else
        return 0;
    return 0;
}
void pwd()
{
    char buf[1024];
    char *cwd =getcwd(buf, sizeof(buf));
    if (NULL == cwd) {
        perror("Get cerrent working directory fail.\n");
        exit(-1);
    } else {
        printf("Current working directory is : %s\n", cwd);
    }
}
void printPID()
{
   char procName[MAX_PROCESS_PATH];
   pid_t pids[32];
   ProcessEntry pes[1024];

   pid_t currPid = getpid();
   printf("pid of this process:%d\n", currPid);
   getNameByPid(currPid, procName);
   printf("task name is %s\n", procName);
   strcpy(procName, "eclipse");
   int pidCount= getPidByName(procName, pids, sizeof pids / sizeof pids[0]);
   int index=0;
   for(index = 0; index < pidCount; index ++)
   {
      printf("pid of process %s: %d\n", procName, pids[index]);
   }

   int procCnt = createProcessSnapshot(pes, sizeof pes / sizeof pes[0]);
   printf("%d processes found.\n", procCnt);
   for(index = 0; index < procCnt; index ++)
   {
      printf("processName: %-16s, pid: %6d\n", pes[index].processName, pes[index].pid);
   }
}
int main()
{
    char cmd[512];
    int flag,i,k,pid;
    char c;
    while(1){
        print();
        k=0;
        //-----------------read command-----------------
        while(1)
        {
            c=getchar();
            if(c!='\n')
                cmd[k++]=c;
            else
            {
                cmd[k++]='\0';
                break;
            }
        }
        //-----------------read command-----------------------
       //------------------Parsing command--------------------
        char *arglist[20]={0};
        char *cp=cmd;
        int args_num=0;
        int len;
        char *start;
        while(*cp!='\0')
        {
            while(*cp==' '||*cp=='\t')
                cp++;
            start=cp;
            len=1;
            c=*++cp;
            while(c!='\0'&&c!='\t'&&c!=' ')
            {
                len++;
                c=*++cp;
            }
            arglist[args_num]=(char *)malloc(len+1);
            strncpy(arglist[args_num],start,len);
            arglist[args_num][len]='\0';
            args_num++;
        }
        //---------Parsing command-----------------------------
        flag=0;
        flag=shellJudgment(arglist,args_num);
	//cd
        if(flag==1)
        {
	    if(strcmp(arglist[0],"cd")==0)
	    {
		if(args_num==1)
		    pwd();
       		else if(args_num==2)
		 {
		   if(chdir(arglist[1])==-1)
			printf("error directory\n");
		 }

  	    }
	    else
		pwd();
        }
        //---------help----------------------------------------
        else if(flag==2)
        {
            printf("______________________________________________________________________________\n");
            printf("The following are the commands and functions of my shell\n");
            printf("command              function\n");
	    printf("______________________________________________________________________________\n");
            printf("cd                   Change the current working directory to another directory\n");
            printf("environ              List all environment variable string settings\n");
            printf("echo<content>        Display the content after echo and wrap\n");
            printf("help                 Display the ways and functions of my shell\n");
            printf("jobs                 Output the current series of sub-processes of the shell, the command and PID of the sub-process must be provided\n");
            printf("quit/exit/bye        Exit the shell\n");
            printf("______________________________________________________________________________\n");

        }
        //-----------------echo---------------------------------------
        else if(flag==4)
        {
            if(args_num==2){
                printf("%s",arglist[1]);
            }
            printf("\n");

        }
        //-----------------Bye----------------------------------------------
        else if(flag==6)
        {
            printf("Bye\n");
            for(i=0;i<args_num;i++)
            {
                free(arglist[i]);
            }
            return 0;
        }
        else if(flag==0)
            printf("error command!\n");
        //-----------------  environ  jobs-----------------------------
        else if(flag==5)//jobs
        {
            printPID();
        }
        else
        {
            pid_t pid;
            /* fork a child process */
            pid = fork();
            if (pid < 0)
            {   /* error occurred */
                fprintf(stderr, "Fork Failed!");
                return 1;
            }
            else if (pid == 0)
            {
                if(flag==3)//environ
                {
                    execlp("env","",NULL);
                    return 0;
                }
            }
            else
            {
                wait(NULL);
            }
        }

    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值