简单模拟实现shell(Linux)

目录​​​​​​​

前言

展示效果

实现代码


前言

该代码模拟了shell的实现,也就是解析类似于"ls -a -l"的命令,当我们启动我们自己写的shell的可执行程序时,我们输入"ls"的命令,也可以展示出在shell中输入"ls"时同样的效果,一下为展示效果

展示效果

当我们在系统的shell下输入"ls"时,会显示

以下代码是我自主模拟实现shell的程序执行"ls"命令时的情况

是不是很类似呢,感兴趣的同学可以看看以下代码,自己也模仿模仿哦ε=ε=ε=(~ ̄▽ ̄)~

实现代码

cs 复制代码
#include <stdio.h>
#include <string.h>
#include <unistd.h>//sleep函数

//wait函数头文件
#include <sys/types.h>
#include <sys/wait.h>

//exit的函数
#include <stdlib.h>

#define NUM 2024
#define SIZE 100
#define SEP " "
//注意是"",而不是''.因为strtok的参数是char*类型

int main()
{
  //0.shell或者软件,只要启动了,使用者不去终止,就始终不能停止,因此要一个死循环
  while (1)
  {
    //1.打印类似于shell命令行前的 [xkjtx@locathost shell@] 的信息
    printf("[xkjtx@locatehost myshell]# ");//不要换行,否则就不像shell了,用fflush去刷新缓冲区,避免没有'\n'而导致的不输出"[xkjtx@locatehost myshell]# "的问题(我在《制作进度条》的那篇博客讲过)
    fflush(stdout);

    //2.获取命令行
    char cmd_line[NUM];//可以定义为全局变量,注意每次使用前memset(cmd_line, '\0', sizeof cmd_line);
    if (fgets(cmd_line, SIZE, stdin) == NULL)//推荐使用fgets,建立对标准输入输出流概念,方便以后学习基础IO
    {
      continue;//读取失败,重新读取
    }

    cmd_line[strlen(cmd_line) - 1] = '\0';

    //char* fgets(char* str, int size, FILE* stream);//如果输入成功,则返回str的起始地址,否则为NULL
    //3.拆分命令行
    char* g_argv[NUM];
    g_argv[0] = strtok(cmd_line, SEP);//第一次调用第一个参数传参目标字符串,后面都传NULL
    int index = 1;


    //使得ls命令时带上颜色
    if (strcmp(g_argv[0], "ls") == 0)
    {
      g_argv[index++] = "--color=auto";
    }
   
    //使得ll命令也可以执行
    if (strcmp(g_argv[0], "ll") == 0)
    {
      g_argv[0] = "ls";
      g_argv[index++] = "-l";
      g_argv[index++] = "--color=auto";
    }
    
    while(g_argv[index++] = strtok(NULL, SEP));

    // printf("index = %d\n", index);


  //  //检测分割是否正确
  // for (index = 0; g_argv[index]; index++)//C99标准不支持在for循环内定义int
  //   printf("g_argv[%d] = %s\n", index, g_argv[index]);
  
    //4.TODO
    //内置命令的处理(要父进程去执行的命令,如cd命令)
    //目前写法发现:cd ~, cd -, rm等命令做不了
    


    //错误写法
    // if (g_argv[0] == "cd")
    if (strcmp(g_argv[0], "cd") == 0)
    {
      if (g_argv[1] != NULL)//路径合法
      {
        chdir(g_argv[1]);
        continue;//不去创建子进程
      }
    }



    //5.创建子进程//好处:不会影响父进程//shell本来就是媒婆招实习生,让实习生干活,不影响媒婆
    pid_t id = fork();
   

    int status = 0;

    if (id == 0)//child
    {
      execvp(g_argv[0], g_argv);//选这个函数的原因:(1)v:用的是数组,恰好有数组  (2)每个都要绝对路径,这是没有必要的,因此可以使用带p的函数
      exit(1);//进行到这里,一定是函数调用失败
    }

    //这里一定是父进程
    //father
    //获取子进程信息
    pid_t ret = waitpid(-1, &status, 0);
    /*
       #include <sys/types.h>
       #include <sys/wait.h>

       pid_t wait(int *status);

       pid_t waitpid(pid_t pid, int *status, int options);

     */
    if (ret > 0) //等待子进程成功
    {
      printf("exit code = %d\n", WEXITSTATUS(status));//打印子进程退出码
    }
  }
  return 0;
}
相关推荐
虾..8 小时前
Linux 软硬链接和动静态库
linux·运维·服务器
Evan芙8 小时前
Linux常见的日志服务管理的常见日志服务
linux·运维·服务器
hkhkhkhkh12310 小时前
Linux设备节点基础知识
linux·服务器·驱动开发
HZero.chen11 小时前
Linux字符串处理
linux·string
张童瑶11 小时前
Linux SSH隧道代理转发及多层转发
linux·运维·ssh
汪汪队立大功12311 小时前
什么是SELinux
linux
石小千11 小时前
Linux安装OpenProject
linux·运维
柏木乃一12 小时前
进程(2)进程概念与基本操作
linux·服务器·开发语言·性能优化·shell·进程
Lime-309012 小时前
制作Ubuntu 24.04-GPU服务器测试系统盘
linux·运维·ubuntu
百年渔翁_肯肯12 小时前
Linux 与 Unix 的核心区别(清晰对比版)
linux·运维·unix