目的:我们要用c语言编写一个shell可以运行在linux机器上的。

介绍:shell所在的层次

我们要做的是操作系统,用于用户与操作系统进行交互的myhsell

思路:用户输入  一行字符串,我们先将其进行切割为一段段的字符串,然后一一匹配判断是内置命令还是 外置命令。内置命令是写在shell程序里面的,而外置命令是单独写的程序,用exec族系统调用。

好,那么下面我们看代码:

  1 #include<stdio.h>
2 #include<unistd.h>
3 #include<sys/wait.h>
4 #include<stdlib.h>
5 #include<pwd.h>
6 #include<string.h>
7 #define MAX_CMD 255
8 #define MAX_DIR_NAME 255
9
10 //help帮助文档
11 int helps(char *inputs[],int i){
12 if(i==1){
13 printf("These shell commands are defined internally. Type 'help' to see this list.\n");
14 printf("Type 'help name' to find out more about the function 'name'\n");
15 return 1;
16 }
17 else if (strcmp(inputs[1],"pwd")==0){
18 printf("pwd:打印当前绝对路径\n");
19 return 1;
20 }else if(strcmp(inputs[1],"cd")==0){
21 printf("cd:可以切换当前目录\n");
22 return 1;
23 } else if(strcmp(inputs[1],"exit")==0){
24 printf("exit:退出shell\n");
25 return 1;
26 } else if(strcmp(inputs[1],"echo")==0){
27 printf("echo:显示并换行\n");
28 return 1;
29 }
30 return 0;
31 }
32
33
34
35 //编写一个外置命令函数专门写内置指令
36 //返回值为1时为成功执行外置指令
37 //返回0时为执行失败不是外置命令
38 int build_out_command(char *inputs[],int i){
39 char path[]="/root/Desktop/codec/myshell/";
40 char buffer[10];
41 bzero(buffer,10);
42 int fd[2];
43 if(pipe(fd)==-1){
44 return 0;
45 }
46 int rc=fork();
47 if(rc<0){
48 return 0;
49 }
50 else if(rc==0){
51 //关掉读
52 close(fd[0]);
53 if(execv(strcat(path,inputs[0]),inputs)<0){
54 write(fd[1],"false",10);
55 }else{
56 write(fd[1],"true",10);
57 }
58 close(fd[1]);
59 exit(0);
60 //结束子进程
61 }else if(rc>0){
62 close(fd[1]);
63 wait(NULL);
64 read(fd[0],buffer,10);
65 if(strcmp(buffer,"false")==0){
66 return 0;
67 }else{
68 return 1;
69 }
70 }
71 }
72
73
74
75
76 //编写一个内置命令函数专门写内置指令
77 //返回值为1时为成功执行内置指令
78 //返回0时为不是内置命令
79 int build_in_command(char cmdstring[],char *inputs[],int i){
80 //1.实现exit退出
81 //printf("inputs[0]=%s",inputs[0]);
82 if(strcmp(inputs[0],"exit")==0){
83 printf("Bye.\n");
84 exit(0);
85 }
86 //2.实现pwd返回目录
87 else if(strcmp(inputs[0],"pwd")==0){
88 char path[MAX_DIR_NAME];
89 memset(path,0,MAX_DIR_NAME);
90 printf("%s\n",getcwd(path,MAX_DIR_NAME));
91 return 1;
92 }
93 //3.实现cd改变目录
94 else if(strcmp(inputs[0],"cd")==0){
95 if(chdir(inputs[1])==0){
96 return 1;
97 }
98
99 }
100 //4.echo显示并换行
101 else if(strcmp(inputs[0],"echo")==0){
102 char *buf1=cmdstring;
103 while(*buf1==' '){
104 buf1++;
105 }
106 while(*buf1!=' '){
107 buf1++;
108 }
109 while(*buf1==' '){
110 buf1++;
111 }
112
113 printf("%s\n",buf1);
114 return 1;
115
116 }
117 //help帮助文档
118 else if(strcmp(inputs[0],"help")==0){
119 int i1= helps(inputs,i);
120 return i1;
121 }
122
123
124
125 return 0;
126 }
127
128
129 struct passwd *pwd1;
130 pwd1=getpwuid(getuid());
131 char path[MAX_DIR_NAME];
132 memset(path,0,MAX_DIR_NAME);
133 getcwd(path,MAX_DIR_NAME);
134 int i=0;
135 int len=strlen(path);
136 char *p=path;
137
138 int i1=len;
139 for(i1;i1>=0;i1--){
140 if(path[i1]=='/'){
141 path[i1]='\0';
142 break;
143 }
144 }
145 for(i;i<=i1;i++){
146 p++;
147 }
148 printf("<%s@localhost :%s#> ",pwd1->pw_name,p);
149 }
150
151
152
153
154
155 //解析指令 例如ls -l ,将该指令分为ls和-l两个字符串分别存储在inputs字符串数数组
156 //返回值是存储的个数最后一位为NULL一共i+1个
157 int parsecommand(char buf[],char *inputs[]){
158 bzero(inputs,MAX_CMD);
159 int in=0;
160 char *p=buf;
161 int i=0;
162 while(*p==' '){
163 p++;
164 i++;
165 }
166 inputs[in]=p;
167 in++;
168 int i1=i;
169 int len=strlen(buf);
170 for(i;i<=len;i++){
171 if(buf[i]==' '){
172 buf[i]='\0';
173
174 }
175 }
176 i1++;
177 p++;
178 for(i1;i1<=len;i1++,p++){
179 if(buf[i1]!='\0'){
180 if(buf[i1-1]=='\0'){
181 inputs[in]=p;
182 in++;
183 }
184
185 }
186 }
187 inputs[in]=NULL;
188
189 return in;
190
191 //一共有in+1个字符串,最后一位NULL
192
193 }
194
195
196 //整体执行函数分为内部命令和外部命令
197 //内部命令直接调用函数执行就好
198 //外部命令自己编写在另一个文件,通过gcc编译
199 //在该函数里通过exec家族函数调用执行
200 int eval(char cmdstring[]){
201 char *inputs[MAX_CMD];
202 char buf[MAX_CMD];
203 strcpy(buf,cmdstring);
204 int i=parsecommand(buf,inputs);
205 //下面实现一些功能
206 //调用内置外置函数
207
208 int returnin=build_in_command(cmdstring,inputs,i);
209 if(returnin==0){
210 int rtout=build_out_command(inputs,i);
211 if(rtout==0){
212 printf("%s: not find command\n",cmdstring);
213 return 0;
214 }
215 }
216 return 1;
217 }
218
219
220
221
222 //main函数通过循环不断接受用户数据
223 //调用eval功能函数实现
224 int main(int argc,char *argv[]){
225 system("stty erase ^H");
226 char cmdstring[MAX_CMD];
227 bzero(cmdstring,MAX_CMD);
228 while(1){
229 attention();
230 fflush(stdout);
231 //读取输入流
232 fgets(cmdstring,MAX_CMD,stdin);
233 //如果没有输入从新开始
234 if(cmdstring[0]=='\n'){
235 continue;
236 }
237 int i=0;
238 for(i;cmdstring[i]!='\n';i++){
239 ;
240 }
241 cmdstring[i]='\0';
242
243 int p=eval(cmdstring);
244 }
245 return 0;
246
247 }
248

外置命令单独写文件

对myshell运行使用几个命令如下:

代码从main函数开始看,如果有不明白的欢迎给我留言哦!!!

linux c语言编写一个shell壳的更多相关文章

  1. 用C语言编写一个简单的词法分析程序

    问题描述: 用C或C++语言编写一个简单的词法分析程序,扫描C语言小子集的源程序,根据给定的词法规则,识别单词,填写相应的表.如果产生词法错误,则显示错误信息.位置,并试图从错误中恢复.简单的恢复方法 ...

  2. 使用Java语言编写一个五子棋UI界面并实现网络对战功能(非局域网)

    使用Java语言编写一个五子棋UI界面并实现网络对战功能(非局域网) 一,前期准备 1,Java IDE(Eclipse)与JDK的安装与配置jdk-15.0.1-免配置路径版提取码:earu免安装版 ...

  3. 用 C 语言编写一个简单的垃圾回收器

    人们似乎觉得编写垃圾回收机制是非常难的,是一种仅仅有少数智者和Hans Boehm(et al)才干理解的高深魔法.我觉得编写垃圾回收最难的地方就是内存分配,这和阅读K&R所写的malloc例 ...

  4. 用Java语言编写一个简易画板

    讲了三篇概博客的概念,今天,我们来一点实际的东西.我们来探讨一下如何用Java语言,编写一块简易的画图板. 一.需求分析 无论我们使用什么语言,去编写一个什么样的项目,我们的第一步,总是去分析这个项目 ...

  5. 《用C++语言编写一个程序,求PI的值》

    //编写一个C++程序求PI的值 /* PI=16arctan(1/5)-4arctan(1/239) 其中arctan用如下形式的极数计算: arctan=x-(x^3/3)+(x^5/7)-(x^ ...

  6. 1.编写一个shell脚本

    一.shell和shell脚本 在linux系统下,以 #/bin/bash开头的文本会被shell解释器进行解释.   shell是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操 ...

  7. 用SMIL语言编写一个简单的演示

    一.首先需要注意的几点是: 1.用记事本编写代码时,要保存为后缀名为.smil或.smi的文件,并且编码格式选择为UTF-8. 2.打开.smil文件的播放器选择为:RealPlayer或是Ambul ...

  8. C语言编写一个简单游戏

    感悟:这算是一个起点吧,我都大二了,还这么菜,才开始写游戏,这个游戏很简单,利用随机数猜大小! #include <stdlib.h> #include <stdio.h> # ...

  9. 编写一个shell脚本来编译并运行java代码

    概述 编译和运行java分别要用到javac命令和java命令,虽然可以使用IDE(比如eclipse,InteliJ,NetBean...),按一下快捷键就可以实现编译并运行,但是,在之前还要配置一 ...

随机推荐

  1. 在Linux命令行内的大小写转换

    在编辑文本时大小写常常是需要注意的地方,大小写的转换是很枯燥而繁琐的工作,所幸,Linux 提供了很多能让这份工作变得容易的命令.接下来让我们看看都有哪些完成大小写转换的命令. tr 命令 tr (t ...

  2. SpringBoot常见注解

    0.前言 这篇文章介绍的 Spring/SpringBoot 常用注解基本已经涵盖你工作中遇到的大部分常用的场景.对于每一个注解我都说了具体用法,掌握搞懂,使用 SpringBoot 来开发项目基本没 ...

  3. 【数论】HAOI2012 容易题

    题目大意 洛谷链接 有一个数列A已知对于所有的\(A[i]\)都是\(1~n\)的自然数,并且知道对于一些\(A[i]\)不能取哪些值,我们定义一个数列的积为该数列所有元素的乘积,要求你求出所有可能的 ...

  4. v-model数据绑定分析

    v-model数据绑定分析 v-model是Vue提供的指令,其主要作用是可以实现在表单<input>.<textarea>及<select>等元素以及组件上创建双 ...

  5. go 协程阻塞

    func main() { wg.Add(2) go test1() go test2() wg.Wait() } func test1() { defer wg.Done() for i:=0;i& ...

  6. nginx优化: timeout超时配置

    一,为什么要做连接超时设置? nginx在保持着与客户端的连接时,要消耗cpu/内存/网络等资源, 如果能在超出一定时间后自动断开连接, 则可以及时释放资源,起到优化性能.提高效率的作用 说明:刘宏缔 ...

  7. 分布式机器学习:如何快速从Python栈过渡到Scala栈

    首先介绍下我的情况和需求,如果你跟我类似,那么这篇文章将很有帮助: 我之前的技术栈主要是Java.Python,机器学习方面主要用到是pandas.numpy.sklearn.scipy.matplo ...

  8. Linux运维学习第三周记

    日落狐狸眠冢上 夜归儿女笑灯前 人生有酒须当醉 一滴何曾到九泉 愿醉卧沙场可未有匹夫之勇. 第三周学记 第三周主要学习正则表达式和Shell编程 1.正则表达式基本字符 2.扩展正则表达式 3.gre ...

  9. linux (简单了解)

    目录 Bash Shell 简单了解 Bash Shell基础语法 一 文件管理 二 用户管理 三权限管理 四 软件管理 什么是Bash Shell 命令的解释,用来翻译用户输入的命令 Bash Sh ...

  10. PostgreSQL 报错 Problem running post-install step.Installation may not complete correctlyThe database cluster initialisation failed.

    在点击完next后安装进度条到最后会弹出题目这个错误 之前选择locale选择china/Singapore 或者china/hongkong都会报错 我的解决方案是 不选择,使用默认的就不会报错,并 ...