设计一个 shell 命令行程序

目录

实现 shell 主要思路 

代码(Linux)系统


实现 shell 主要思路 

1、要知道一个 shell 进程在运行起来都会在命令行呈现什么,如图是Xshell 登录成功后的界面:所以第一步要做的就是打印命令行提示符。

Xshell 命令行提示符的组成是:[用户名@主机名 工作目录]$,那么我们自己 shell 的命令行提示符就可以按照 Xshell 的为模板,用户名,主机名,工作目录这些可以通过环境变量(USER,HOSTNAME,PWD)来获取。

用户在输入的时候,会在命令与选项之间加上空格,所以不能使用 scanf 来输入,所以要使用 fgets或 gets 来获取用户输入。C语言默认打开三个默认输入输出流:stdin(键盘),stdout(显示器),stderror(显示错误信息)

但是在输入的时候,会默认加上一个回车(Enter),这就使得我们输入的字符串后面会有一个‘\n’,所以需要将 '\n' 的位置改为'\0'。

最后返回输入命令字符串的长度,方便后面判断命令字符串是否只有‘\n’。

2、然后就是获取用户在命令行输入的字符串,并且将这一个大字符串分割形成一个个子字符串,将分割形成的这些字符串作为参数,传递给 exec 系列的接口来实现程序替换。

在C语言中使用 strtok 函数,在C++ 中使用 string 的 substr 接口。用C语言 strtok 实现如下:

宏定义的SEP 是字符串分割符,“ ”(空格),具体参考strtok函数,它第一次需要传要分割的字符串,后面传 NULL ,每次返回一个被分割的子串。

将这些被分割的字符存入一个char* 类型的数组,结束当分割结束时,strtok 函数返回 NULL,刚好作为数组的最后一个元素,作为数组的最后一个元素,也方便后期调用 exec 系列的接口。

3、实现进程替换功能

因为之前已经将用户输入的字符串分割成子串放入 srgv 数组中了,所以argv[0] 和 argv 数组恰好匹配 execvp接口的两个参数,父进程用 rid 通过status 输出型参数在 waitpid 接口中获取子进程的退出码。

4、运行内建命令

有些命令在我们设计的 shell 中运行无效,如 cd、export、echo等,因为我们在执行的时候是让myshell 产生的子进程在执行命令,而像 cd、export、echo 这种,只有让父进程 bash 自己执行才有效的,这种命令叫内建命令。

内建命令就是 bash 自己执行的,类似于自己内部的一个函数,所以需要在进行进程替换前先判断用户输入的命令是否是内建命令,穷举出内建命令并以此比较,如果是某一内建命令就直接执行,如果不是内建命令就进行程序替换!

5、将 myshell 程序设置成一个死循环,使其可以一直执行打印命令行提示符、获取用户命令字符串,实现程序替换功能。

这个程序和系统的shell 程序一样,都是“死循环”,只能手动终止!

代码(Linux)系统

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>
#define NUM 1024
#define SIZE 64
#define SEP " "
//#define Debug 1
char cwd[NUM];
char enval[NUM];
int lastcode = 0; //exit code
// get environment variable
const char* getUsername()
{
  const char* name = getenv("USER");
  if(name) return name;
  else return "none";
}
const char* getHostname()
{
  const char* host = getenv("HOSTNAME");
  if(host) return host;
  else return "none";
}
const char* getCwd()
{
  const char* cwd = getenv("PWD");
  if(cwd) return cwd;
  else return "none";
}
int getUserCommand(char* command, int num)
{
  printf("[%s@%s %s]#", getUsername(), getHostname(), getCwd());
  char* r = fgets(command, num, stdin); // still have a '\' in the end when you input
  if(r == NULL) return -1;
  // remove the '\n'
  command[strlen(command) - 1] = '\0'; // input's input  at least have a '\n', so dont't will crossed
#ifdef Debug 
   printf("%s", usercommand); //test
#endif
  return strlen(command);
}
void commandSplit(char* in, char* out[])
{
  int argc = 0;
  out[argc++] = strtok(in, SEP);
  while(out[argc++] = strtok(NULL, SEP));
#ifdef Debug
  for(int i = 0; out[i]; i++)
  {
    printf("%d:%s\n", i, out[i]);
  }
#endif
}
int execute(char* argv[])
{
  pid_t id = fork();
  if(id < 0) return -1;
  else if(id == 0) // child 
  {
    // process replace   exec command
    execvp(argv[0], argv);
    exit(1);
  }
  else // father
  {
    int status = 0;
    pid_t rid = waitpid(id, &status, 0);
    if(rid > 0){ // wait success
      lastcode = WEXITSTATUS(status);
    }
  }
  return 0;
}
void cd(char* path)
{
  chdir(path);
  char tmp[NUM];
  getcwd(tmp, sizeof tmp);
  sprintf(cwd, "PWD=%s", tmp);
  putenv(cwd);
}
int doBulidin(char* argv[])
{
  if(strcmp(argv[0], "cd") == 0)
  {
    char* path = NULL;
    if(argv[1] == NULL) path = ".";
    else path = argv[1];
    cd(path);
    return 1;
  }
  else if(strcmp(argv[0], "export") == 0)
  {
    if(argv[1] == NULL) return 1;
    strcpy(enval, argv[1]);
    putenv(enval);
    return 1;
  }
  else if(strcmp(argv[0], "echo") == 0)
  {
    char *val = argv[1] + 1; // $PATH  $?
    if(strcmp(val, "?") == 0) {
      printf("%d\n", lastcode);
      lastcode = 0;
    }
    else {
      printf("%s\n", val);
    }
    return 1;
  }
  return 0;
}
int main()
{
  while(1){
      char usercommand[NUM]; // store user's input
      char* argv[SIZE]; // a table store commands
      // getUsercommand and print command_line prompt
      int n = getUserCommand(usercommand, sizeof(usercommand));
      if(n <= 0) continue; // if only have a '\n'
      // split commands and store in array
      commandSplit(usercommand, argv);
      n = doBulidin(argv); // check or do bulidin_command
      if(n) continue;
      execute(argv);
  }   
}

总结:本质上说,自己设计一个 shell 进程,就是进行多次的程序替换。 

附:进程替换(函数)接口

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/407390.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SQL-Labs46关order by注入姿势

君衍. 四十六关 ORDER BY数字型注入1、源码分析2、rand()盲注3、if语句盲注4、时间盲注5、报错注入6、Limit注入7、盲注脚本 四十六关 ORDER BY数字型注入 请求方式注入类型拼接方式GET报错、布尔盲注、延时盲注ORDER BY $id 我们直接可以从界面中得知传参的参数为SORT&#x…

力扣 169. 多数元素

思路&#xff1a; 因为题目说一定存在多数元素&#xff0c;就说明一定有一个数的个数多于n/2 将数组采用冒泡从小到大排序&#xff0c;最中间的那个元素一定是多数元素&#xff08;因为在大小排好序后&#xff0c;中位数也一定是众数&#xff09; 答案&#xff1a; int maj…

【鸿蒙 HarmonyOS 4.0】UIAbility、页面及组件的生命周期

一、背景 主要梳理下鸿蒙系统开发中常用的生命周期 二、UIAbility组件 UIAbility组件是一种包含UI界面的应用组件&#xff0c;主要用于和用户交互。 UIAbility组件是系统调度的基本单元&#xff0c;为应用提供绘制界面的窗口&#xff1b;一个UIAbility组件中可以通过多个页…

数据价值在线化丨TiDB 在企查查数据中台的应用及 v7.1 版本升级体验

本文介绍了企查查在数据中台建设中使用 TiDB 的经验和应用。通过从 MySQL 到 TiDB 的迁移&#xff0c;企查查构建了基于 TiDB Flink 的实时数仓框架 &#xff0c;充分利用了 TiDB 的分布式架构、MySQL 兼容性和完善的周边工具等特性&#xff0c;实现了数据的在线化处理。2023 年…

svn客户端下载、安装、使用

下载、使用 打开360软件管家&#xff0c;选怎宝库&#xff0c;搜索svn&#xff0c;点击安装 可以修改安装路径 使用 在桌面右键弹出菜单&#xff0c;点击 输入地址&#xff0c;点击ok 输入用户名、密码 &#xff0c;等待检出完成

Java智慧工地管理云平台源码 带AI识别、桌面管理+大屏指挥+手机APP

目录 智慧工地云系统技术说明 1.什么是 AI 危险源识别 2.什么是标养室监测 3.什么是塔机监测 4.什么是塔机黑匣子 5.什么是升降机监测 6.什么是升降机黑匣子 7.什么是标养箱 8.什么是吊钩可视化 9.什么是吊钩追踪控制设备 10.什么是扬尘监测 11.什么是扬尘监测设备…

基于SpringBoot的停车场管理系统

基于SpringBootVue的停车场管理系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatis工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 前台首页 停车位 个人中心 管理员界面 摘要 摘要&#xff1a;随着城市化进程的…

测绘测量行业CRM功能大揭秘:哪家才是最佳选择?

测绘测量行业面临着处理及管理海量数据的难题。办公软件进行数据记录是非常繁琐的&#xff0c;往往需要花费大量的时间来查找所需的信息&#xff0c;甚至造成内容丢失。测绘测量企业运用CRM管理系统至关重要。本文将向您介绍测绘测量行业CRM功能、哪家好&#xff1f; CRM软件的…

03 表数据基本操作

文章目录 插入(insert)查询(select)where子句更新表记录(update)删除表记录&#xff08;delete&#xff09;表字段的操作(alter)时间类型数据 插入(insert) insert into 表名 values(值1&#xff0c;值2...),(值1&#xff0c;值2...),...; insert into 表名 (字段1,...) value…

【办公类-16-10-02】“2023下学期 6个中班 自主游戏观察记录(python 排班表系列)

背景需求&#xff1a; 已经制作了本学期的中4班自主游戏观察记录表 【办公类-16-10-01】“2023下学期 中4班 自主游戏观察记录&#xff08;python 排班表系列&#xff09;-CSDN博客文章浏览阅读398次&#xff0c;点赞10次&#xff0c;收藏3次。【办公类-16-10-01】“2023下学…

Python零基础安装教程(包含各种安装方案)以及PyCharm安装步骤

文章目录 安装方案介绍安装Python解释器安装Pycharm安装Anaconda方案参考 安装方案介绍 方案1&#xff1a;只安装Python解释器&#xff08;适合小型开发&#xff09; 方案2&#xff1a;安装集成开发环境Anaconda&#xff08;集成了Spyder&#xff0c;JupyterNotebook等编辑器&…

代码随想录算法训练营Day27 || leetCode 93.复原IP地址 || 78.子集 || 90.子集II

93.复原IP地址 与分割回文串的代码相近&#xff0c;先写出判断函数&#xff0c;之后以判断结果为标准&#xff0c;执行回溯的代码。此题中使用点的个数来决定回溯的终止&#xff0c;需要学习一下。 class Solution { private:vector<string> result;bool isValid(const …

从事游戏开发类职业岗位的任职资格

游戏开发工程师主要是指致力于游戏总体设计&#xff0c;负责游戏开发和维护工具的设计与开发工作。并配合主程序完成游戏架构的设计&#xff0c;与其他技术支持的工作。从事这项工作&#xff0c;需要掌握的知识和技能非常多&#xff0c;下面就跟着小编来一起了解一下吧。 1、任…

高级RAG:使用RAGAs + LlamaIndex进行RAG评估,包括原理、图和代码

原文地址&#xff1a;Using RAGAs LlamaIndex for RAG evaluation 2024 年 2 月 5 日 如果您已经为实际的业务系统开发了检索增强生成&#xff08;Retrieval Augmented Generation, RAG&#xff09;应用程序&#xff0c;那么您可能会关心它的有效性。换句话说&#xff0c;您…

Vulhub 靶场训练 DC-8解析

一、环境搭建 kali的IP地址&#xff1a;192.168.200.14 DC-8的IP地址&#xff1a;192.168.200.13&#xff08;一个flag&#xff09; 靶机和攻击机处于同一个网络方式&#xff1a;nat或桥接 若出现开机错误&#xff0c;适当将dc的兼容版本改低&#xff0c;我的vmware workst…

【黑马程序员】1、TypeScript介绍_黑马程序员前端TypeScript教程,TypeScript零基础入门到实战全套教程

课程地址&#xff1a;【黑马程序员前端TypeScript教程&#xff0c;TypeScript零基础入门到实战全套教程】 https://www.bilibili.com/video/BV14Z4y1u7pi/?share_sourcecopy_web&vd_sourceb1cb921b73fe3808550eaf2224d1c155 目录 1、TypeScript介绍 1.1 TypeScript是什…

Dear ImGui的UE5.3集成实践

Dear ImGui一直较为火热&#xff0c;这是一个调试使用并且可以响应快速迭代的Gui库&#xff0c;甚至可以做到在任何代码块中调用API即显示。如果你想更多的了解一下可访问其官方网站&#xff1a;https://www.dearimgui.org/ 那么本文就来在UE5中尝试踩坑使用它。 UE4.26版本 …

什么是抖音视频下载软件|视频批量下载|爬虫工具

抖音视频抓取软件是一款方便用户获取抖音平台上视频内容的工具。它具备以下主要功能&#xff1a; 批量视频提取&#xff1a;用户可以输入关键词&#xff0c;软件将自动搜索抖音平台上与关键词相关的视频&#xff0c;并将它们列出供用户选择和下载。用户可以随时停止搜索和下载过…

猫头虎分享已解决Bug || 语法错误:SyntaxError: Unexpected token < in JSON at position 0

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

一文看懂大模型 Sora 技术推演

sora 一出&#xff0c;引起社会各界广泛关注。中美AI的差距进一步扩大&#xff0c;中美人才培养体系的差距等等言论&#xff0c;甚嚣尘上。 其实文生视频领域&#xff0c;华人学者和产业界的参与度还是非常高的。 那么 Sora 到底是谁做的&#xff0c;怎么做的&#xff0c;本篇…