【Linux】自定义shell(命令行解释器)

原理: shell是命令行解释器,当有命令需要执行时,shell创建子进程,让子进程执行命令,而shell只需等待子进程退出即可。

其中我们使用了下面这几个函数:

  • 获取命令行(fgets函数)。
  • 解析命令行(strtok分割字符串)。
  • 创建子进程(fork函数)。
  • 替换子进程(exec函数族)。
  • 等待子进程退出(waitpid函数)

 实现简易命令解释行的过程中我们遇到了一些问题:

cd,export等內键命令,在子进程下修改无法影响到bash,所以我们增加了函数来判断命令是否为內键命令,并判断其是否为空,使用chdir修改其所在路径通过argv[1]取出要到的路径。

但是我们发现如果进入的是..  上级路径的话 就会变成下面这样

 

我们的目录名称直接变成了..,此时我们需要使用 snprintf函数 将temp写入pwd中。

以下为简易实现的代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>
#define SIZE 1024
#define MAX_ARGC 64
#define SEP " "
char *argv[MAX_ARGC];
char PWD[SIZE];
 const char* HostName()
 {
    char *hostname=getenv("HOSTNAME");
    if(hostname) return hostname;
    else return "none";
 }
 const char* UserName()                       
 {                                            
   char *hostname=getenv("USER");         
   if(hostname) return hostname;              
   else return "none";                        
 }         
 const char* CurrentWorkDir()   
 {                    
   char *hostname=getenv("PWD");         
   if(hostname) return hostname;              
   else return "none";                        
 }  
 char *Home()
 {
   return getenv("HOME");
 }
 int Interactive(char out[],int size)
 {
                                                                                                                                                                                                   
   printf("[%s@%s %s]$",UserName(),HostName(),CurrentWorkDir());
   fgets(out,size,stdin);
   out[strlen(out)-1]=0;//'\0'
   return strlen(out);
 }
void Split(char in[])
 {
   int i=0;
   argv[i++]=strtok(in,SEP);
     while(argv[i++]=strtok(NULL,SEP));
 }
 void Execute()
 {
 pid_t id=fork();
 if(id==0)
 {
   execvp(argv[0],argv);
   exit(1);
 }
   pid_t rid=waitpid(id,NULL,0);
   printf("run done,rid: %d\n",rid);
 }
 int BuildinCmd()
 {
   int ret=0;
   //1.检测是否为内建命令 是1 否0
   if(strcmp("cd",argv[0])==0)                                                                                                                                                                     
   {
     ret=1;
     char *target=argv[1];
     if(!target) target=Home();
     chdir(target);
     char temp[1024];
      getcwd(temp,1024);
      snprintf(PWD,SIZE,"PWD=%s",temp);
      putenv(PWD);
  }
   //2.执行
   return ret;
 }
 int main()
 {
  //1.打印命令行提示符,获取用户输入的命令字符串
  while(1)
  {
   char commandline[SIZE];
   int n= Interactive(commandline,SIZE);
   if(n==0) continue;
   //2.对命令行进行切割
   Split(commandline);
   //3.处理内建命令
   n=BuildinCmd();
   if(n) continue;
   //4.执行这个命令
   Execute();
  }
   //int j=0;
   //for(j=0;argv[j];j++)
   //{
   //  printf("argv[%d]: %s\n",j,argv[j]);
   //}
   return 0;
 }                                       

 Makefile文件的配置:

myshell:myshell.c
		gcc -o $@ $^ 
.PHONY:clean
	rm -f myshell

演示结果如下

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值