Linux 写一个自己的bash版本3.0(收官)

在mybash的3.0版本中,作者改进了之前的bash实现,使用自己编写的ls和pwd命令替代系统命令,并通过修改替换进程代码段,实现了通过自定义路径调用这些命令。通过定义宏变量PATH指定命令所在路径,根据命令前缀判断执行方式,成功调用了mybin目录下的命令。文章提供了完整代码,并建议读者尝试将系统命令复制到mybin目录以测试mybash的功能。
摘要由CSDN通过智能技术生成

写一个自己的bash3.0版本(收官)

1、问题描述

我们已经完成了写一个自己的bash1.0版本写一个自己bash2.0版本在2.0版本中我们改善了1.0版本,让程序打印命令提示符的时候可以自动获取用户名,主机名,当前位置和自动判断当前是管理员用户#还是普通用户$和自己实现了内置命令cd,但是仍有一些缺陷,当启动mybash可执行程序,输入ps,ls,pwd等命令时,mybash是fork一个子进程,然后替换该子进程来实现调用命令,可这些ps,ls,pwd等命令是系统已经提供好的,execvp函数会自动从环境变量$PATH所指出的路径中查找可执行程序。那么我们可以自己写ls,pwd等命令,然后mybash去调用自己的命令吗?当然可以!!!在博客Linux自己实现pwd和ls命令中已经完成pwd命令和ls命令的实现。那么今天的3.0版本中,就改进自己的bash用自己的命令。

2、重写替换进程代码段

2.1因为用自己写的命令,所以替换进程函数改用execv,自己指定路径,首先找出自己写的命令所在路径
在这里插入图片描述
在代码中定义一个宏变量

 #define PATH "/home/wys/mycode/day18/mybin/"

2.2想一想执行可执行文件常用哪几种方式,1. ./main 在当前路径 2. /home/wys/mycode/main 给出绝对路径 3./home/wys/mycode/ 给出路径然后在该路径下找到可执行文件,考虑这三种情况,用execv的时候我们也要分三种情况
2.3重新编写替换进程片段代码

       pid_t pid = fork();
       if(pid == -1 )
       {
         printf("fork error\n");
       }

       if(pid == 0 )
       {
         char path[128] = { 0 };
         if(strncmp(cmd,"./",2) == 0 || strncmp(cmd,"/",1) == 0 )
         {
            strcpy(path,cmd);
         }
         else
         {
             strcpy(path,PATH);
             strcat(path,cmd);
         }
         execv(path,myargv);
         printf("exec error\n");
         exit(0);

2.4编译运行
在这里插入图片描述
调用自己/home/wys/mycode/day18/mybin目录下的命令成功,因为mybin目录下只有ls和pwd可执行文件,执行ps不等替换进程成功。
在这里可以重新实验一下,咱们把/usr/bin/目录下的ps拷贝到mybin目录下,看看能不能通过mybin目录来调用ps成功。
在这里插入图片描述
重新执行mybash
在这里插入图片描述
子进程被mybin目录下的ps替换成功

3、完整代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
#include<pwd.h>
#include<errno.h>
#define PATH "/home/wys/mycode/day18/mybin/"

char* get_cmd (char buff[],char* myargv[])
{

   if( buff == 0 || myargv == 0)
   {
      return NULL;

   }
   char*s = strtok(buff," ");
   int i = 0;
   while( s != NULL )
   {
      myargv[i++] = s;
      s = strtok(NULL," ");
   }
   return myargv[0];
}

void print_info()
{

    int id = getuid();//获取用户id
    char* s = "$";
    if( id  == 0 )
    {
       s = "#";
    }

    struct passwd* ptr = getpwuid(id);//通过uid获取用户详细信息
    if( ptr == NULL )
    {
      printf("$");
      fflush(stdout);
      return;
    }

    char hostname[64] = { 0 };
    if (gethostname(hostname,64) == -1 )
    {
      printf("$");
            fflush(stdout);
      return;
    }

    //获取当前位置
    char pwd_buff[128] = {0};
    if(getcwd(pwd_buff,128) == NULL)
    {
      printf("$");
      fflush(stdout);
      return;
    }

    //打印命令提示行信息
    printf("\033[1;32;40m %s@%s:\033[0m \033[1;34;40m%s%s\033[0m",ptr->pw_name,hostname,pwd_buff,s);
    fflush(stdout);
}
 int main()

 {
  while(1)
  {
    char buff[128] = { 0 };
    print_info();
    fgets(buff,128,stdin);
    buff[strlen(buff) - 1] = 0;
    char* myargv[10] = { 0 };
    char* cmd = get_cmd(buff,myargv);
    if(cmd == NULL)
    {
        continue;
    }
    else if (strcmp(cmd,"exit") == 0 )
    {
       exit(0);
    }
    else if (strcmp(cmd,"cd") == 0)
    {
        if( myargv[1] == NULL )
        {
            continue;
        }
        if ( chdir(myargv[1]) == -1)
        {
            perror("cd err");
        }
        continue;
    }
    else
    {
       pid_t pid = fork();
       if(pid == -1 )
       {
         printf("fork error\n");
       }

       if(pid == 0 )
       {
         char path[128] = { 0 };
         if(strncmp(cmd,"./",2) == 0 || strncmp(cmd,"/",1) == 0 )
         {
            strcpy(path,cmd);
         }
         else
         {
             strcpy(path,PATH);
             strcat(path,cmd);
         }
         execv(path,myargv);
         printf("exec error\n");
         exit(0);
       }
      wait(NULL);
    }
  }
  exit(0);
}

4、结束语

在这里那一个简单的mybash就完成了,当然大家可以继续改进它,比如自己去写ps命令然后去实现。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WYSCODER

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值