[Linux入门]---使用exec函数实现简易shell

文章目录

  • 1.简易实现
  • 2.人机交互,获取命令行
  • 3.命令行分割
  • 4.执行命令
  • 5.内建命令
  • 6.myshell代码

1.简易实现

2.人机交互,获取命令行

代码如下:

int quit=0;
#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define LINE_SIZE 1024char pwd[LINE_SIZE];
char commandline[LINE_SIZE];const char* getusername()
{return getenv("USER");
}void getpwd()
{getcwd(pwd, sizeof(pwd));
}
void interact(char* cline, int size)
{//获取主机名char hostname[256];gethostname(hostname, sizeof(hostname));//获取当前路径getpwd();printf(LEFT"%s@%s %s"RIGHT""LABLE" ", getusername(),hostname, pwd);char* s = fgets(cline, size, stdin);assert(s);//debug版本下assert才起效果//release,assert失效(void)s;//使用一下,可以在不同版本都生效,抵挡编译器报警//"abcd\n\0"cline[strlen(cline)-1] = '\0';
}
int main()
{while(!quit){//交互问题,获取命令行interact(commandline,sizeof(commandline));printf("%s\n",commandline );}return 0;
}

代码运行的的结果为:
在这里插入图片描述
运行结果如上,程序获取命令行以及提示行显示的功能已经完成了。

3.命令行分割

代码如下:

#define DELIM " "
#define ARGC_SIZE 32char* argv[ARGC_SIZE];int splitstring(char cline[], char* _argv[])
{int i = 0;_argv[i++] = strtok(cline, DELIM);//stork函数扫描字符串末尾时,返回空指针while(_argv[i++] = strtok(NULL,DELIM));//故意写的=return i - 1;
}
int main()
{while(!quit){//交互问题,获取命令行interact(commandline,sizeof(commandline));//3.子串分割问题,解析命令行int argc = splitstring(commandline,argv);if(argc == 0) continue;for(int i = 0; i < argc; i++){printf("%s\t",argv[i]);}printf("\n");}return 0;
}

代码运行的的结果为:
在这里插入图片描述
运行结果如上,命令行分割成字符串并存放进入数组使用。

4.执行命令

代码如下:

#define EXIT_CODE 44int lastcode = 0;void NormalExcute(char* _argv[])
{pid_t id = fork();if(id < 0){perror("fork");return;}else if(id == 0){//让子进程执行命令execvp(_argv[0],_argv);exit(EXIT_CODE);}else{int status = 0;pid_t rid = waitpid(id, &status,0);if(rid == id){lastcode = WEXITSTATUS(status);}}
}
int main()
{while(!quit){//1.交互问题,获取命令行interact(commandline,sizeof(commandline));//2.子串分割问题,解析命令行int argc = splitstring(commandline,argv);if(argc == 0) continue;for(int i = 0; i < argc; i++){//printf("%d:",i);//printf("%s\n",argv[0]);printf("%s\n",argv[i]);}printf("\n");//3.普通命令的执行//if(!n)NormalExcute(argv);}return 0;
}

代码运行的结果:
在这里插入图片描述
运行结果如上,可以让子进程执行替换函数,调用系统程序命令执行!

5.内建命令

在这里插入图片描述
我们发现使用一些命令的时候没有结果,诸如“”cd\echo”等命令,因为这些命令属于内建命令,是要父进程执行的。
代码如下:

#define EXIT_CODE 44int lastcode = 0;//自定义环境变量表
char myenv[LINE_SIZE];
//自定义本地变量表int buildCommand(char* _argv[], int _argc)
{if(_argc == 2 && strcmp(_argv[0], "cd") == 0){//修改父进程中的当前路径chdir(argv[1]);//把修改路径放到pwd数组中getpwd();//把pwd数组的路径,放到环境变量中sprintf(getenv("PWD"), "%s", pwd);return 1;}else if(_argc == 2 && strcmp(_argv[0], "export") == 0){strcpy(myenv, _argv[1]);putenv(myenv);//增加环境变量到父进程中return 1;}else if(_argc == 2 && strcmp(_argv[0], "echo") == 0){if(strcmp(_argv[1],"$?") == 0){printf("%d\n", lastcode);lastcode=0;}else if(*_argv[1] == '$'){char* val = getenv(_argv[1]+1);if(val) printf("%s\n", val);}return 1;}//特殊处理一下if(strcmp(_argv[0], "ls") == 0){_argv[_argc++] = "--color";_argv[_argc] = NULL;}return 0;
}
int main()
{while(!quit){//1.交互问题,获取命令行interact(commandline,sizeof(commandline));//2.子串分割问题,解析命令行int argc = splitstring(commandline,argv);if(argc == 0) continue;for(int i = 0; i < argc; i++){//printf("%d:",i);//printf("%s\n",argv[0]);printf("%s\n",argv[i]);}printf("\n");//指令的判断//内建命令,本质就是一个shell内部的一个函数int n = buildCommand(argv, argc);//3.普通命令的执行if(!n) NormalExcute(argv);}return 0;
}

代码运行的结果如下:
在这里插入图片描述
在执行普通命令之前,我们需要判断是不是内建命令,如果是的话,分析之后让父进程执行!

6.myshell代码

#include <stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define LINE_SIZE 1024
#define DELIM " "
#define ARGC_SIZE 32
#define EXIT_CODE 44int quit=0;
char pwd[LINE_SIZE];
char commandline[LINE_SIZE];
char* argv[ARGC_SIZE];
int lastcode = 0;//自定义环境变量表
char myenv[LINE_SIZE];
//自定义本地变量表const char* getusername()
{return getenv("USER");
}
//const char* gethostname()
//{
//    return getenv("HOSTNAME");
//}
const char* mygethostname()
{//char myhostname[LINE_SIZE];return getenv("HOSTNAME");
}
void getpwd()
{getcwd(pwd, sizeof(pwd));
}
void interact(char* cline, int size)
{//获取主机名char hostname[256];gethostname(hostname, sizeof(hostname));//获取当前路径getpwd();//printf("%s\n",mygethostname());//printf(LEFT"%s@%s%s"RIGHT""LABLE" ",getusername(),mygethostname(),pwd);printf(LEFT"%s@%s %s"RIGHT""LABLE" ", getusername(),hostname, pwd);char* s = fgets(cline, size, stdin);assert(s);//debug版本下assert才起效果//release,assert失效(void)s;//使用一下,可以在不同版本都生效,抵挡编译器报警//"abcd\n\0"cline[strlen(cline)-1] = '\0';
}int splitstring(char cline[], char* _argv[])
{int i = 0;_argv[i++] = strtok(cline, DELIM);//stork函数扫描字符串末尾时,返回空指针while(_argv[i++] = strtok(NULL,DELIM));//故意写的=return i - 1;
}void NormalExcute(char* _argv[])
{pid_t id = fork();if(id < 0){perror("fork");return;}else if(id == 0){//让子进程执行命令execvp(_argv[0],_argv);exit(EXIT_CODE);}else{//创建子进程失败int status = 0;pid_t rid = waitpid(id, &status,0);if(rid == id){lastcode = WEXITSTATUS(status);}}
}
int buildCommand(char* _argv[], int _argc)
{if(_argc == 2 && strcmp(_argv[0], "cd") == 0){//修改父进程中的当前路径chdir(argv[1]);//把修改路径放到pwd数组中getpwd();//把pwd数组的路径,放到环境变量中sprintf(getenv("PWD"), "%s", pwd);return 1;}else if(_argc == 2 && strcmp(_argv[0], "export") == 0){strcpy(myenv, _argv[1]);putenv(myenv);//增加环境变量到父进程中return 1;}else if(_argc == 2 && strcmp(_argv[0], "echo") == 0){if(strcmp(_argv[1],"$?") == 0){printf("%d\n", lastcode);lastcode=0;}else if(*_argv[1] == '$'){char* val = getenv(_argv[1]+1);if(val) printf("%s\n", val);}return 1;}//特殊处理一下if(strcmp(_argv[0], "ls") == 0){_argv[_argc++] = "--color";_argv[_argc] = NULL;}return 0;
}
int main()
{while(!quit){//1.交互问题,获取命令行interact(commandline,sizeof(commandline));//2.子串分割问题,解析命令行int argc = splitstring(commandline,argv);if(argc == 0) continue;//指令的判断//内建命令,本质就是一个shell内部的一个函数int n = buildCommand(argv, argc);//3.普通命令的执行if(!n) NormalExcute(argv);}return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

布偶猫应该喂什么猫罐头:交响乐金罐、希喂、尾巴生活测评

布偶猫&#xff0c;萌宠界的甜心代表&#xff0c;爱撒娇又黏人。想让它健康成长&#xff1f;喂养是关键。选粮不当&#xff0c;健康受损。今日精选三款热门主食罐&#xff0c;依据布偶猫营养需求&#xff0c;直接评测&#xff0c;助你快速了解何为理想之选。无需繁琐&#xff0…

Geneformer中文教程(2).huggingface transformers

Geneformer基于hugging face的transformers实现&#xff0c;具体模型是BertForSequenceClassification&#xff0c;本篇先熟悉该模型。 首先直观看Geneformer的模型架构&#xff0c;基于BERT构建一个文本分类模型&#xff0c;我们直接从预训练的Geneformer加载BERT&#xff0c…

为什么mac打不开rar文件 苹果电脑打不开rar压缩文件怎么办

你是否遇到过这样的情况&#xff0c;下载了一个rar文件&#xff0c;想要查看里面的内容&#xff0c;却发现Mac电脑无法打开。rar文件是一种常见的压缩文件格式&#xff0c;它可以将多个文件或文件夹压缩成一个文件&#xff0c;节省空间和传输时间。如此高效实用的压缩文档&…

自动驾驶:LQR、ILQR和DDP原理、公式推导以及代码演示(七、CILQR约束条件下的ILQR求解)

&#xff08;七&#xff09;CILQR约束条件下的ILQR求解 CILQR&#xff08;(Constrained Iterative Linear Quadratic Regulator)&#xff09; 是为了在 iLQR 基础上扩展处理控制输入和状态约束的问题。在这种情况下&#xff0c;系统不仅要优化控制输入以最小化代价函数&#x…

Python 课程9-資料庫操作

前言 在现代软件开发中&#xff0c;数据库是核心组件之一&#xff0c;它负责数据的存储、管理和检索。无论是简单的应用程序还是复杂的企业级系统&#xff0c;数据库操作都是必不可少的。本教程将深入讲解如何使用 Python 进行数据库操作&#xff0c;涵盖使用 sqlite3 进行本地…

《论网络安全体系设计》写作框架,软考高级系统架构设计师

论文真题 随着社会信息化的普及&#xff0c;计算机网络已经在各行各业得到了广泛的应用。目前&#xff0c;绝大多数业务处理几乎完全依赖计算机和网络执行&#xff0c;各种重要数据如政府文件、工资档案、财务账目和人事档案等均依赖计算机和网络进行存储与传输。另一方面&…

从用户数据到区块链:Facebook如何利用去中心化技术

在数字化时代&#xff0c;用户数据的管理和保护已成为科技公司面临的重大挑战。作为全球最大的社交网络平台之一&#xff0c;Facebook不仅在用户数据的处理上积累了丰富的经验&#xff0c;也在探索如何利用去中心化技术&#xff0c;如区块链&#xff0c;来改进其数据管理和用户…

Kafka原理剖析之「Topic创建」

一、前言 Kafka提供了高性能的读写&#xff0c;而这些读写操作均是操作在Topic上的&#xff0c;Topic的创建就尤为关键&#xff0c;其中涉及分区分配策略、状态流转等&#xff0c;而Topic的新建语句非常简单 bash kafka-topics.sh \ --bootstrap-server localhost:9092 \ // …

【刷题】Day4--密码检查

Hi&#xff01; 今日刷题&#xff0c;小白一枚&#xff0c;欢迎指导 ~ 【链接】 密码检查_牛客题霸_牛客网 【思路】 依次根据规则判断密码是否合格。while里嵌套个for循环&#xff0c;来进行密码的多组输入&#xff0c;for循环进行一次代表判断一个密码串&#xff1b;规则…

springboot请求传参常用模板

注释很详细&#xff0c;直接上代码 项目结构 源码 HelloController package com.amoorzheyu.controller;import com.amoorzheyu.pojo.User; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.web.bind.annotation.*;import java.ti…

2024桥梁科技两江论坛——第二届桥梁工程安全与韧性学术会议

文章目录 一、会议详情二、重要信息三、大会介绍四、出席嘉宾五、征稿主题六、咨询 一、会议详情 二、重要信息 大会官网&#xff1a;https://ais.cn/u/vEbMBz提交检索&#xff1a;EI Compendex、IEEE Xplore、Scopus 三、大会介绍 2024年桥梁科技两江论坛——第二届桥梁工程…

一种简单的过某宝验证码的方式(仅做学习使用)

开篇 今天介绍一种简单的过某宝验证码的方式&#xff0c;用的是自动化&#xff0c;这样对不会js逆向的小白非常友好&#xff0c;只需要用到selenium框架就能轻松过某宝验证码&#xff0c;即模拟人的操作对滑块进行滑动。 但是首先还是需要训练验证码和标题 训练前&#xff1a…

基于微信小程序的图书馆预约占座系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 基于微信小程序JavaSpringBootVueMySQL的图…

GD - GD32350R_EVAL - PWM实验和验证3 - EmbeddedBuilder - 无源蜂鸣器 - 用PMOS来控制

文章目录 GD - GD32350R_EVAL - PWM实验和验证3 - EmbeddedBuilder - 无源蜂鸣器 - 用PMOS来控制概述笔记失败图成功图蜂鸣器管脚波形总结END GD - GD32350R_EVAL - PWM实验和验证3 - EmbeddedBuilder - 无源蜂鸣器 - 用PMOS来控制 概述 以前做了一个实验&#xff0c;用PMOS来…

智能智造和工业软件研发平台SCSAI功能介绍

用爱编程30年&#xff0c;倾心打造工业和智能智造软件研发平台SCIOT,用创新的方案、大幅的让利和极致的营销&#xff0c;致力于为10000家的中小企业实现数字化转型&#xff0c;打造数字化企业和智能工厂&#xff0c;点击上边蓝色字体&#xff0c;关注“AI智造AI编程”或文末扫码…

element-plus表单使用show-overflow-tooltip,避免占满屏幕,需要设置宽度

在表单中&#xff0c;<el-table-clumn>中添加show-overflow-tooltip&#xff0c;可以实现表格内容过多的问题。 属性官方解释&#xff1a;是否隐藏额外内容并在单元格悬停时使用 Tooltip 显示它们。 出现的问题&#xff1a; 使用了该属性之后&#xff0c;弹出的详细内…

Linux 手动安装Ollama

Linux 离线安装Ollama 前言 不知道为什么 在阿里云服务器上 执行curl -fsSL https://ollama.com/install.sh | sh一键安装 非常慢 所以只能手动装了 1.到 https://ollama.com/install.sh 下载安装执行文件 修改其中 下载和安装部分代码 if curl -I --silent --fail --location…

形态学算法(连通分量提取,区域最大值提取)

文章目录 二值图像形态学算法连通分量提取 灰度图形态学算法灰度重建区域最大值查找 本文先列举一些近期用到的形态学算法&#xff0c;以后可能会再进行补充。 二值图像形态学算法 连通分量提取 在上一篇文章中已经提到连通分量的概念&#xff0c;这里再进行回顾&#xff1a;…

go 笔记

数据结构与 方法&#xff08;增删改查&#xff09; 安装goland,注意版本是2024.1.1&#xff0c;不是2024.2.1&#xff0c;软件下载地址也在链接中提供了 ‘go’ 不是内部或外部命令&#xff0c;也不是可运行的程序 或批处理文件。 在 Windows 搜索栏中输入“环境变量”&#…

SurfaceTexture OnFrameAvailableListener 调用流程分析

背景: 最近项目中遇到一个问题, 需要搞清楚OnFrameAvailableListener 回调流程, 本文借此机会做个记录, 巩固印象, 有相关困惑的同学也可以参考下. 本文基于Android 14 framework 源码进行分析 SurfaceTexture.java OnFrameAvailableListener 设置过程 public void setOnFra…