从零开始学习Linux(8)----自定义shell

shell从用户读入字符串“ls”,shell建立一个新的进程,然后在那个进程中运行ls程序并等待那个进程结束。然后shell读取新的一行输入,建立一个新的进程,在这个进程中运行程序,并等待这个进程结束。所以要写一个shell,需要循环以下过程:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>#define SIZE 1024
#define MAX_ARGC 64
#define SEP " " // 命令参数之间的分隔符// 全局变量
char *argv[MAX_ARGC]; // 用于存储解析后的命令行参数
char pwd[SIZE]; // 当前工作目录
char env[SIZE]; // for test
int lastcode = 0; // 最后一个子进程的退出状态// 获取主机名
const char* HostName()
{char *hostname = getenv("HOSTNAME"); // 从环境变量中获取HOSTNAME if(hostname) return hostname; // 如果找到,返回主机名else return "None";// 否则返回"None"
}// 获取用户名
const char* UserName()
{char *username = getenv("USER");if(username) return username; // 如果找到,返回用户名else return "None"; // 否则返回"None"
}// 获取当前工作目录
const char *CurrentWorkDir()
{char *pwd = getenv("PWD"); // 应该是从环境变量中获取PWD if(pwd) return pwd; // 如果找到,返回当前工作目录 else return "None"; // 否则返回"None"
}// 获取用户主目录
char *Home()
{return getenv("HOME"); // 从环境变量中获取HOME
}// 与用户进行交互,获取命令字符串
int Interactive(char out[], int size)
{// 输出提示符并获取用户输入的命令字符串"ls -a -l"printf("[%s@%s %s]$ ", UserName(), HostName(), CurrentWorkDir());fgets(out, size, stdin);// 从标准输入读取一行out[strlen(out)-1] = 0; //'\0', commandline是空串的情况?// 移除字符串末尾的换行符'\n' return strlen(out);// 返回命令字符串的长度(不包括末尾的'\0')
}// 分割用户输入的命令字符串为参数数组
void Split(char in[])
{int i = 0; argv[i++] = strtok(in, SEP); // "ls -a -l"// 使用空格作为分隔符分割字符串,并将第一个参数存入argv[0] while(argv[i++] = strtok(NULL, SEP)); // 故意将== 写成 =// 继续分割并存储剩余参数// 下面的代码块试图修改参数列表以在ls命令后添加"--color"if(strcmp(argv[0], "ls") ==0){argv[i-1] = (char*)"--color";// 这会覆盖最后一个参数argv[i] = NULL;// 确保argv数组以NULL结尾 }
}// 执行命令
void Execute()
{pid_t id = fork();// 创建一个新的子进程if(id == 0){// 在子进程中执行命令 execvp(argv[0], argv);// 使用环境变量中的PATH来查找要执行的程序 exit(1);// 如果execvp失败(例如找不到程序),则退出子进程并返回1 }int status = 0;pid_t rid = waitpid(id, &status, 0);// 在父进程中等待子进程结束if(rid == id) lastcode = WEXITSTATUS(status); // 如果子进程正常结束,获取其退出状态并保存//printf("run done, rid: %d\n", rid);
}int BuildinCmd()
{int ret = 0;// 检测 argv[0] 是否为 "cd",如果是则执行 cd 命令 // 1. 检测是否是内建命令, 是 1, 否 0if(strcmp("cd", argv[0]) == 0){// 2. 执行// 标记为内建命令 ret = 1;// 获取 cd 命令的参数(要切换到的目录),如果没有参数则默认为家目录 char *target = argv[1]; //cd XXX or cdif(!target) target = Home();// 如果没有指定目录,则切换到用户家目录// 切换到目标目录chdir(target);// 获取当前工作目录并保存到 temp 变量中char temp[1024];getcwd(temp, 1024);// 构造新的环境变量 "PWD",并将其设置为当前工作目录 snprintf(pwd, SIZE, "PWD=%s", temp);putenv(pwd);}// 检测 argv[0] 是否为 "export",如果是则执行 export 命令else if(strcmp("export", argv[0]) == 0){ret = 1;// 如果有参数,则将其设置为环境变量if(argv[1]){strcpy(env, argv[1]);putenv(env);}}// 检测 argv[0] 是否为 "echo",如果是则执行 echo 命令 else if(strcmp("echo", argv[0]) == 0){ret = 1;// 如果没有参数,则输出一个换行符 if(argv[1] == NULL) {printf("\n");}else{// 如果参数以 '$' 开头,则进行特殊处理 if(argv[1][0] == '$'){// 如果参数是 "$?",则输出上一个命令的退出状态if(argv[1][1] == '?'){printf("%d\n", lastcode);lastcode = 0;}else{// 否则,获取环境变量并输出其值 char *e = getenv(argv[1]+1);if(e) printf("%s\n", e);}}else{// 如果参数不是以 '$' 开头,则直接输出该参数 printf("%s\n", argv[1]);}}}return ret;
}int main()
{while(1){char commandline[SIZE];// 1. 打印命令行提示符,获取用户输入的命令字符串int n = Interactive(commandline, SIZE);if(n == 0) continue;// 2. 对命令行字符串进行切割Split(commandline);// 3. 处理内建命令n = BuildinCmd();if(n) continue;// 4. 执行这个命令Execute();}// for(int i=0; argv[i]; i++)// {// printf("argv[%d]: %s\n", i, argv[i]);// }return 0;
}
相关文章:
从零开始学习Linux(8)----自定义shell
shell从用户读入字符串“ls”,shell建立一个新的进程,然后在那个进程中运行ls程序并等待那个进程结束。然后shell读取新的一行输入,建立一个新的进程,在这个进程中运行程序,并等待这个进程结束。所以要写一个shell&…...
《大数据分析-数据仓库项目实战》学习笔记
目录 基本概念 数据仓库 数据仓库整体技术架构 数据仓库主题 数据集市 数据仓库的血缘关系 数据仓库元数据管理 数据仓库的指标 数据仓库维度概念 HDFS Flume Hadoop Kafka 数据仓库分层模型 Superset 即席查询 Sqoop Atlas元数据管理 项目需求描述 系统目标…...
JDK介绍
JDK是Java Development Kit的缩写,是Oracle公司提供的用于开发Java应用程序的开发包。它包括了Java运行环境(Java Runtime Environment),以及一系列Java工具(如javac、java、jdb等)和Java基础类库ÿ…...
JavaScript 对象入门:基础用法全解析
目录 对象 语法 属性和访问 方法和调用 this关键字 null 遍历对象 内置对象 Math 属性 方法 Date 创建日期对象 获取和设置日期 ⭐对象 对象是 JavaScript 数据类型的一种,数据类型也包括数值类型、字符串类型、布尔类型、undefined。对象数据类型可…...
如何获得一个Oracle 23ai数据库(docker容器)
准确的说,是Oracle 23ai Free Developer版,因为企业版目前只在云上(OCI和Azure)和ECC上提供。 方法包括3种,本文介绍第3种: Virtual ApplianceRPM安装Docker 我已经有了一台Oracle Linux 8的虚机&#x…...
想跨境出海?云手机提供了一种可能性
全球化时代,越来越多的中国电商开始将目光投向了海外市场。这并不是偶然,而是他们在长期的市场运营中,看到了出海的必要性和潜在的机会。 中国的电商市场无疑是全球最大也最发达的之一。然而,随着市场的不断发展和竞争的日益加剧…...
制药行业新突破:CANOpen转PROFINET网关配置案例解析
在药品制造工业环境中,实现CanOpen转Profinet协议之间转换的网关配置是一个关键过程,确保了不同通信协议的设备能够互相协作。以开疆智能CanOpen转Profinet网关为例,以下是其配置流程:首先安装CanOpen转Profinet网关的配置软件&am…...
vue前端时间段选择控件
实现效果: 可选具体的某天的某时某分某秒 vue前端代码: <el-form-item label"日期"><el-date-pickerv-model"daterangerq"style"width: 240px"value-format"yyyy-MM-dd HH:mm:ss"type"datetimerange"range-separat…...
用wordpress建外贸独立站的是主流的外贸建站方式
WordPress因其易用性、灵活性和强大的功能支持,成为了外贸企业首选的网站建设平台。 从技术和功能角度来看,WordPress提供了丰富的主题和插件,这些都是构建专业外贸网站所必需的。例如,有专门为外贸网站设计的主题和插件…...
差异基因散点图绘制教程
差异基因散点图绘制教程 本期教程 小杜的生信笔记,自2021年11月开始做的知识分享,主要内容是R语言绘图教程、转录组上游分析、转录组下游分析等内容。凡事在社群同学,可免费获得自2021年11月份至今全部教程,教程配备事例数据和相…...
Windows安装多版本MySQL
5.7 - 配置 my.ini [client] port 3307[mysql] default-character-set utf8mb4[mysqld] port 3307 server_id 1 character-set-server utf8mb4basedir "E://MySQL/mysql5.7" datadir "E://MySQL/mysql5.7/data"# 将所有表名转换为小写字母 lower_c…...
Redis7降级到Redis6如何AOF备份恢复(错的)
Redis7降级到Redis6如何AOF备份恢复(错的) 前提:从始至终开启AOF 介绍的Docker安装的Redis,不是Docker也一样,差不多 一、data目录差异 redis版本7 - /data/appendonlydir - appendonly.aof.manifest - appendo…...
通过EXCEL控制PLC启停电机的一种方法
概述 本例将介绍用微软EXCEL电子表格控制西门子S7-1200 PLC实现电机启停的一种方法。 第1步: 添加PLC设备,选择西门子S7-1214C CPU,设置IP地址:192.168.18.18,子网掩码:255.255.255.0。 第2步:…...
【GPT4O 开启多模态新时代!】
系列文章目录 GPT-4o的出现,让 AI 真正进入了全能时代,而且 OpenAI 宣布所有人免费使用! 不论你是需要写文章、听声音还是看视频,GPT-4o都能满足你的需求 文章目录 系列文章目录什么是GPT-4o?一、GPT-40 的新功能二、…...
HTTP协议及Python实现
最近的项目需要频繁在前后端之间传输数据,本篇主要介绍HTTP协议以及数据传输方法。 1 HTTP协议 1.1 http协议简介 HTTP(Hypertext Transfer Protocol)是一种用于传输超文本数据的应用层协议。它是万维网上数据交换的基础,定义了客户端和服务器之间进行通…...
【机器学习】逻辑化讲清PCA主成分分析
碎碎念:小编去年数学建模比赛的时候真的理解不了主成分分析中的“主成分”的概念!!但是,时隔两年,在机器学习领域我又行了,终于搞明白了!且看正文!再分享一个今天听到的播客中非常触…...
Vue常见的指令
Vue.js 提供了许多内置指令,这些指令可以在模板中用于处理元素的显示、行为等。以下是 Vue.js 中常见的 7 个指令及其详细代码示例: 1、v-bind:用于属性绑定,可以动态更新 HTML 属性。 html<template> <div> <img…...
【Ansible】ansible-playbook剧本
playbook 是ansible的脚本 playbook的组成 1)Tasks:任务;通过tasks 调用ansible 的模板将多个操作组织在一个playbook中运行 2)Variables:变量 3)Templates:模板 4)Handles…...
Linux的命令
; 昨天学习了七个命令,分别是:cd命令(切换目录)、pwd命令(当前目录)、mkdir命令(创建目录)、touch命令(创建文件)、date命令(显…...
No known conditions for “./lib/locale/lang/zh-cn“ entry in “element-plus“ pa
yarn的安装和卸载 npm install -g yarn npm uninstall yarn -g //yarn卸载 改用yarn卸载试试 先安装yarn npm install -g yarn 卸载掉原来的element-plus yarn remove element-plus 重新安装原有的element-plus版本 yarn add element-plus2.3.1 低版本页面引用为 i…...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
