前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【Linux】手把手教你制作一个简易shell——(进程创建fork进程替换wait与进程等待exec的应用)(自定义shell程序设计)

【Linux】手把手教你制作一个简易shell——(进程创建fork进程替换wait与进程等待exec的应用)(自定义shell程序设计)

作者头像
YY的秘密代码小屋
发布于 2024-09-24 11:27:10
发布于 2024-09-24 11:27:10
18700
代码可运行
举报
文章被收录于专栏:C++系列C++系列
运行总次数:0
代码可运行

前言 大家好吖,欢迎来到 YY 滴Linux系列 ,热烈欢迎! 本章主要内容面向接触过C++ Linux的老铁 主要内容含:

一.前置知识

【1】Shell和Bash简述

  • Shell 是一种命令行界面,是用户与系统之间的接口,允许用户执行命令来 管理系统资源、运行程序等
  • Bash 是 Shell 的一种实现,也是目前最流行的 Shell 之一

【2】Bash的输入原理——指针数组

  1. 我们运行Linux时会出现, bash提示符和命令行 ,我们接下来也要实现这两点
  2. 本质是通过 空格 作为分隔符,把一个一个字符串分隔开载入 指针数组中 ;
  3. 在父进程bash进程中,创建一个子进程,环境变量也会传递给子进程,并进行 进程等待wait
  1. 在子进程中通过 进程替换exec ,执行 指针数组中 中的命令(通过环境变量)

ifn<=0,直接结束省的创建子进程

cd就不行。因为是子进程的cd…

二.自定义shell程序设计

【1】<主函数模块>——大体框架

1.程序设计框架
  • 根据前置知识中的实现原理
  • 我们主函数中要有对应模块:
  1. 打印提示符&&获取用户命令字符串获取成功: getUserCommand函数
  2. 分割字符串: commandSplit函数
  3. 执行对应的命令: execute函数
2.程序设计细节
  1. 设置一个命令行获取字符数组:usercommand
  2. 设置一个存储———分割usercommand数组后的字符串的地址——的指针数组:argv
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#define NUM 1024
#define SIZE 64

int main()
{
    while(1){  //shell要不停跑,死循环
    
        char usercommand[NUM];
        char *argv[SIZE];
        // 1. 打印提示符&&获取用户命令字符串获取成功
        int n= getUserCommand(usercommand, sizeof(usercommand));
        // 2. 分割字符串
        // "ls -a -l" -> "ls" "-a" "-l"
        commandSplit(usercommand, argv);
        // 3. 执行对应的命令
        execute(argv);
    }
}

【2】<打印提示符>模块

1.程序设计框架
  • 提示符信息包括:1.HOME 2.USER 3.HOSTNAME
  • 我们将上面3个信息分别封装,在getUserCommand函数中统一打印
  • 我们通过getenv函数可以获取 环境变量的地址,进而打印
  • command参数 接收命令行获取 字符数组usercommand
  • num参数 接收 字符数组长度
2.程序设计细节
  1. C语言默认会打开三个输入输出流:stdin键盘 stdout显示器stderr显示器,我们用到stdin获取输入流
  2. 不用scanf,用fget函数的原因:scanf遇到空格停下来,命令行本身就会出现空格。故采用行获取接口fgets
  1. command参数 接收命令行获取 字符数组usercommand ,我们输入命令后,最终你还是会输入\n——导致执行结果和shell之间出现空行;所以我们在输入完后要把command最后一个字符'\n'换成'\0'
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int getUserCommand(char *command, int num)
{
    printf("[%s@%s %s]# ", getUsername(), getHostname(), getCwd());
    char *r = fgets(command, num, stdin); // 最终你还是会输入\n
    if(r == NULL) return -1;
    // "abcd\n" "\n"
    command[strlen(command) - 1] = '\0'; // 有没有可能越界?不会
    return strlen(command);
}

char *homepath()
{
    char *home = getenv("HOME");
    if(home) return home;
    else return (char*)".";
}

const char *getUsername()
{
    const char *name = getenv("USER");
    if(name) return name;
    else return "none";
}
const char *getHostname()
{
    const char *hostname = getenv("HOSTNAME");
    if(hostname) return hostname;
    else return "none";
}

【3】<分割字符串>模块

1.程序设计框架
  • 这个模块,我们要通过 空格 作为分隔符,把一个一个字符串分隔开载入 指针数组 argv
  • in参数 接收命令行获取 字符数组usercommand
  • *out[]参数 输出型参数,用于传出 分割usercommand数组后的字符串的地址——的指针数组argv
2.程序设计细节
  • 通过strstok函数分割; 注意语法,分成首次分割,和剩余分割
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#define SEP " "
void commandSplit(char *in, char *out[])
{
    int argc = 0;
    out[argc++] = strtok(in, SEP);
    while( out[argc++] = strtok(NULL, SEP));
}

【4】<执行对应的命令>模块

1.程序设计框架

我们回顾原理部分:

  • 在父进程bash进程中,创建一个子进程,环境变量也会传递给子进程,并进行 进程等待wait
  • 在子进程中通过 进程替换exec ,执行 指针数组中 中的命令(通过环境变量)

于是我们设计出:

  1. fork函数创建子进程
  2. 子进程进行进程替换execvp函数,用到 分割usercommand数组后的字符串的地址——的指针数组argv
  3. 父进程等待子进程
2.程序设计细节

1. fork函数:

2. execvp函数: 由于我们用到了指针数组argv,所以用exec系列的vp尾缀,execvp 表示v(vector)数组,p(可以使用环境变量PATH,无需写全路径)

3. waitpid函数:不关心后续操作,status参数设置成NULL,options参数设置成0

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int execute(char *argv[])
{
    pid_t id = fork();
    if(id < 0) return -1;
    else if(id == 0) //child
    {
        // exec command
        execvp(argv[0], argv); // cd ..
        exit(1);
    }
    else // father
    {
        int status = 0;
        pid_t rid = waitpid(id, NULL, 0);
    }
    return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-09-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
vue 报错-Module not found: Error: Can't resolve 'element-plus' in '
在运行项目的时候,会出现这样的报错 error in ./src/util/service.js Module not found: Error: Can't resolve 'element-plus' in 'D:\BaiduNetdiskDownload\code\src\util' 解决办法 安装 element-plus模块 npm install element-plus --save 再次运行 既可以成功
王小婷
2022/10/04
3K0
vue 报错-Module not found: Error: Can't resolve 'element-plus' in '
vue3+element-plus+router+vuex+axios从零开始搭建(1)vue3+element-plus
1.下载node, 不要使用最新的版本element-plus组件没支持到最新的版本。
solate
2021/06/21
3.1K0
vue3+element-plus+router+vuex+axios从零开始搭建(1)vue3+element-plus
vue踩坑-Error: Can't resolve 'sass-loader' in 'E:\Element-UI-master\src\components'
好了 完美解决Error: Can't resolve 'sass-loader' in 'E:\Element-UI-master\src\components'的问题了。
王小婷
2019/08/23
6.5K0
vue踩坑-Error: Can't resolve 'sass-loader' in 'E:\Element-UI-master\src\components'
vue项目安装element报错:npm error code ERESOLVE npm error ERESOLVE unable to resolve de
这个错误是由 依赖冲突 引起的,特别是在你的项目中使用了 vue@3.5.13 版本,但你同时安装了 element-ui@2.15.14,该版本的 element-ui 依赖于 vue@^2.5.17。而 element-ui 仅支持 Vue 2.x 版本,所以导致了这个依赖冲突。
肥晨
2024/12/06
6300
vue 报错:Module not found:Error:Can't resolve 'vuex' in XXX
在vue的组件里面 引用import { useStore } from 'vuex'的时候 出现了这样的报错
王小婷
2022/09/28
1.7K0
vue  报错:Module  not found:Error:Can't resolve 'vuex' in XXX
Module not found: Error: Can't resolve '@/components/achievement/echartsPage' in '/app/src/views/ach
cat src/views/achievement/CategoryDepart.vue
程裕强
2020/03/18
2.5K0
Vue3 + Vite + TypeScript 项目搭建总结
node 版本>=12.0.0,这边建议直接更新到 16+(我本地的是最新的 v20.11.1)
zz_jesse
2024/05/02
6000
Vue3 + Vite + TypeScript 项目搭建总结
Syntax Error: Error: Cannot find module ‘node-sass‘
启动vue项目的时候,会出现这样的报错 Syntax Error: Error: Cannot find module ‘node-sass’
王小婷
2025/05/19
890
Syntax Error: Error: Cannot find module ‘node-sass‘
mac下使用vue create 项目名称 创建项目后无法运行ERROR  Error: Cannot find module 'vue-template-compiler/package.json'
promote:vue_pro wangxinqiang$ npm run serve
botkenni
2019/09/03
6.1K0
mac下使用vue create 项目名称 创建项目后无法运行ERROR  Error: Cannot find module 'vue-template-compiler/package.json'
Vue2.0 新手完全填坑攻略——从环境搭建到发布
Homebrew 1.0.6(Mac)、Node.js 6.7.0、npm 3.10.3、webpack 1.13.2、vue-cli 2.4.0、Atom 1.10.2
onety码生
2018/11/21
1.8K0
mongodb踩坑-Error: Cannot find module 'mongoose'
在输入命令npm start启动运行项目的时候,有时候会遇到这样的错误Error: Cannot find module 'mongoose',缺少mongoose这个模块。
王小婷
2020/12/01
8500
node环境之Error: Cannot find module ‘chalk’ 报错无法解决的问题—-网上说让你npm install chalk 基本是没有
node环境之Error: Cannot find module ‘chalk’ 报错无法解决的问题—-网上说让你npm install chalk 基本是没有用的-优雅草央千澈解决方案
卓伊凡
2024/12/31
4520
如何解决 Module build failed: Error: Cannot find module ‘node-sass‘ 报错问题
在进行前端开发时,特别是使用 Webpack 或其他构建工具时,我们可能会遇到如下的错误信息:
猫头虎
2025/03/31
8170
【实战技巧】Vue3+Vite工程常用工具的接入方法
Vue3 正式版已经发布一段时间了,和 Vue3 更配的工具 Vite 也已经投入使用了,本文整理了如何将一些常用的工具整合到项目中。
一尾流莺
2022/12/10
2.1K0
阅读源码 -【vite项目架构】
为了省事,我们可以在项目架构时就把一切都准备好,虽然配置起来有点烦人,但是这样写项目的时候真的很方便很丝滑。
y191024
2023/08/22
5030
阅读源码 -【vite项目架构】
Vue3 全家桶 + Element Plus + Vite + TypeScript + Eslint 项目配置最佳实践
而且 Element Plus + Vite 也出了一段时间了,是时候该上手体验分享一波了。
Sneaker-前端公虾米
2021/06/21
2.6K1
Vue3 全家桶 + Element Plus + Vite + TypeScript + Eslint 项目配置最佳实践
umi3升级umi4报错问题汇总,附解决方法
删除 package.json 中的 react-dev-inspector ,从新 yarn 一下:
德顺
2023/08/25
4.6K0
Vue 2 教程菜鸟
遇到:Module build failed: Error: Cannot find module '模块名'
zhangjiqun
2024/12/16
1470
Vue 2 教程菜鸟
Vue + TypeScript + Element 项目实战及踩坑记
本文讲解如何在 Vue 项目中使用 TypeScript 来搭建并开发项目,并在此过程中踩过的坑 。
夜尽天明
2019/06/03
4.7K0
vue踩坑-This relative module was not found
相对应的模块没找到 calendar.vue 这个组件没找到,位置在Header.vue,把路径改下就行了。
王小婷
2025/05/18
1200
vue踩坑-This relative module was not found
推荐阅读
相关推荐
vue 报错-Module not found: Error: Can't resolve 'element-plus' in '
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验