最新设计一个 shell 命令行程序_设计 个shell程序,从入门到真香

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

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
  {


![img](https://img-blog.csdnimg.cn/img_convert/0ef9638dea393e956c61c8d3a8453b31.png)
![img](https://img-blog.csdnimg.cn/img_convert/8e4172da41d1da3af78ee825f28ac127.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值