0
点赞
收藏
分享

微信扫一扫

【Linux】简陋shell原理 + 实现

SDKB英文 2022-04-27 阅读 42

一、命令行信息提示格式

xshell的命令行

image-20220427133251704

持续等待输入

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

#define NUM 128 //指令长度

int main()
{
  char commond[NUM];//指令

  while(1)
  {
    //清空字符串
    commond[0] = 0;

    printf("[Rinne@windows 11 xsehll]# ");
    fflush(stdout);//标准输出进行刷新
    sleep(1);
  }
  return 0;
}

image-20220427133441946


二、获取指令

根据之前所学,指令可以拿数组存放

image-20220427133556542

scanf不行,因有空格会停下

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

#define NUM 128 //指令长度

int main()
{
  char command[NUM];//指令

  while(1)
  {
    //清空字符串
    command[0] = 0;

    printf("[Rinne@windows 11 xsehll]# ");
    fflush(stdout);//标准输出进行刷新
    fgets(command, NUM, stdin);
    printf("echo: %s\n", command);
  }
  return 0;
}

image-20220427134124013

如果输入错误ctrl + delete删除


这里发现多了一个\n是我们输入的时候回车时候的那个\n

  while(1)
  {
    //清空字符串
    command[0] = 0;

    printf("[Rinne@windows 11 xsehll]# ");
    fflush(stdout);//标准输出进行刷新
    fgets(command, NUM, stdin);
    command[]
    printf("echo: %s\n", command);
  }

三、分割指令

使用strtok函数

image-20220427142058539

第一次调用strtok函数时,传递原始字符串以及分解字符串

之后再调用strtok函数时,只需要传递NULL和分解字符串

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

#define SZ 64 
#define NUM 128 //指令长度

int main()
{
  char command[NUM];//指令

  while(1)
  {

    char* argv[SZ] = {NULL};
    
    //清空字符串
    command[0] = 0;

    printf("[Rinne@windows 11 xsehll]# ");
    fflush(stdout);//标准输出进行刷新
    fgets(command, NUM, stdin);
    command[strlen(command) - 1] = 0;

    const char* seek = " ";
    argv[0] = strtok(command, seek);
    int i = 1;
    while(argv[i] = strtok(NULL, seek))
    {
      i++;
    }

    //check
    for(size_t j = 0; argv[j]; j++)
    {
      printf("%s\n", argv[j]);
    }
  }
  return 0;
}

image-20220427143629894


四、创建子进程进行程序替换(执行命令行)

xshell的命令的传参方式和execvp很像

ls          -l -a -d
//文件名    //如何执行,指令字符串

int execlp(const char *file, const char *arg, ...);

argv[0]是个字符串,程序本身的文件名。比如ls -a,ls存在argv[0]是文件名

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

#define SZ 64 
#define NUM 128 //指令长度

int main()
{
  char command[NUM];//指令

  while(1)
  {

    char* argv[SZ] = {NULL};
    
    //清空字符串
    command[0] = 0;

    printf("[Rinne@windows 11 xsehll]# ");
    fflush(stdout);//标准输出进行刷新
    fgets(command, NUM, stdin);
    command[strlen(command) - 1] = 0;

    const char* seek = " ";
    argv[0] = strtok(command, seek);
    int i = 1;
    while(argv[i] = strtok(NULL, seek))
    {
      i++;
    }

    //check
    /*for(size_t j = 0; argv[j]; j++)
    {
      printf("%s\n", argv[j]);
    }*/

    if(fork()==0)
    {
      execvp(argv[0], argv);
      exit(1);
    }

    waitpid(-1, NULL, 0);

  }
  return 0;
}

image-20220427150752488

但这是简陋的xshell,| 、 > 都不认识


五、创建内建命令

这里进行多次cd,目录都没有改变

image-20220427151251788

总结:凡是usr/bin/目录下的指令都是创建子进程进行的

如果要内建命令方式,改变父进程:

image-20220427151055842

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

#define SZ 64 
#define NUM 128 //指令长度

int main()
{
  char command[NUM];//指令

  while(1)
  {

    char* argv[SZ] = {NULL};
    
    //清空字符串
    command[0] = 0;

    printf("[Rinne@windows 11 xsehll]# ");
    fflush(stdout);//标准输出进行刷新
    fgets(command, NUM, stdin);
    command[strlen(command) - 1] = 0;

    const char* seek = " ";
    argv[0] = strtok(command, seek);
    int i = 1;
    while(argv[i] = strtok(NULL, seek))
    {
      i++;
    }

    //check
    /*for(size_t j = 0; argv[j]; j++)
    {
      printf("%s\n", argv[j]);
    }*/

    if(strcmp(argv[0], "cd") == 0)
    {
      if(argv[1] != NULL)
      {
        chdir(argv[1]);
        continue;
      }
    }

    if(fork()==0)
    {
      execvp(argv[0], argv);
      exit(1);
    }

    waitpid(-1, NULL, 0);

  }
  return 0;
}

image-20220427153036867


举报

相关推荐

0 条评论