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

导读:本篇文章讲解 Linux 写一个自己的bash版本3.0(收官),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

写一个自己的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命令然后去实现。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/95568.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!