在学习了Linux的进程控制之后,学习了fork函数和exec函数族,通过这些个函数可以简单的实现一份shell,就是实现一份命令行解释器,当然是简单版的,实现功能如下

  1. 能执行普通的命令如ls ,ps ,top等
  2. 可以实现目录的跳转cd命令
  3. 能执行命令并加上参数如ls-l
  4. 能执行打开man手册
  5. 能识别管道符

还不能实现正则表达式,要实现这个我当前的代码根本不能用,要重头开始改写。。。

下面贴代码

 #include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <pwd.h>
#include <sys/utsname.h>
#include <libgen.h> void eatblank(char **buf)
{
while(**buf==' ')
{
(*buf)++;
}
} void GetHostName(char *hostname,int length)
{
gethostname(hostname,length);
char *p=hostname;
while(*p!='\0')
{
if(*p=='.')
{
*p='\0';
}
p++;
}
} void Pipe(char **my_argv,char *buf);
void BuildCommand(char **my_argv,char *buf)
{
eatblank(&buf);
my_argv[]=buf;
int index=;
char *p=buf;
while(*p!='\0')
{
if(*p==' ')
{
*p='\0';
p++;
eatblank(&p) ;
if(*p!='|')
{
my_argv[index++]=p;
}
continue;
}
else if(*p=='|')
{
p++;
//p++;
my_argv[index]=NULL;
Pipe(my_argv,p);
}
else
{
p++;
}
}
my_argv[index]=NULL;
} void Pipe(char ** my_argv,char *buf)
{
int fd[];
pipe(fd);
pid_t id2=fork();
if(id2==)
{
close();
dup(fd[]);
close(fd[]);
close(fd[]);
execvp(my_argv[],my_argv);
}
else
{
waitpid(id2,NULL,);
close();
dup(fd[]);
close(fd[]);
close(fd[]);
BuildCommand(my_argv,buf);
execvp(my_argv[],my_argv);
}
//在此处添加exec族函数
} int main()
{
while()
{
char *my_argv[];
struct passwd *pwd=getpwuid(getuid());
char hostname[]={'\0'};
char cwd[]={'\0'};
getcwd(cwd,);
GetHostName(hostname,);
printf("[%s@%s %s]#",pwd->pw_name,hostname,basename(cwd));
fflush(stdout);
char buf[];
buf[]='\0'; int count=read(,buf,sizeof(buf));
buf[count-]='\0';
my_argv[]=buf;
pid_t id=fork();
if(id==)
{
//child if(strncmp(buf,"cd",)==)
{
exit();
}
BuildCommand(my_argv,buf);
execvp(my_argv[],my_argv);
printf("if the process has some problem ,I should run here\n");
exit();
}
else
{
//father
int status=;
wait(&status);
if(status==)
{
my_argv[]+=;
chdir(my_argv[]);
}
}
}
return ;
}

通过gethostname获取主机名,通过getcwd获得当前工作目录,通过getpwuid获得当前登录的用户信息

这样命令提示符就完成了;

  • 普通命令的实现

普通命令的实现并不困难,我的目的是让子进程来执行命令,也就是通常的让fork产生的子进程执行exec族函数,然后自己死掉,通过父进程回收资源,循环并创建新的子进程,这就是shell的大框架,其中用execvp函数来实现命令的执行,函数原型就不多说了,查手册就能查到,简单解释一下参数,第一个参数是命令行的字符串,第二是参数是一个字符串数组,从上到下依次存放,命令,参数(可能有多个,一个参数占一个下标),最后用NULL占据一个下标表示结束。

  • cd命令的实现

cd命令的实现有些问题,不是普通命令的实现,就是说简单的使用execvp是不能实现的,因为就算子进程改变了目录之后也会把自己杀死,父进程和子进程之间是不通的(就是说父进程和子进程并不共享环境变量,子进程修改了当前工作目录的环境变量对父进程也没有什么影响),后来使用system来执行系统调用,也失败,因为更多时候shell会产生一个子进程来执行命令,因为shell本身执行会有风险,可能会因为用户的错误操作把自己挂掉,所以使用子进程来执行命令,而这样和刚才的结果是一样的并不会影响到父进程,最后采用了chdir函数,他可以改变当前进程的环境变量中的工作目录(就是专门change dir用的),让父进程来执行,fork出来的子进程会有一份父进程环境变量的拷贝,这就完成了改变目录,并将结果传递了下来

  else
{
//father
int status=;
wait(&status);
if(status==)
{
my_argv[]+=;
chdir(my_argv[]);
}
}
  • 管道符的实现

管道符的实现很简单,平常我们执行命令的时候,都是结果自动输出到电脑屏幕上,这说明一般命令的输出是write在标准输出stdout的,而我们输出命令的参数是通过键盘,这说明命令的输入来源是标准输入stdin,如果我们关闭了,标准输出和标准输入,而是通过一个管道,让结果写进管道,然后让参数从管道中读取(简单的说就是让管道的两段代替标准输入和标准输出),管道符就实现了

 void Pipe(char ** my_argv,char *buf)
{
int fd[];
pipe(fd);
pid_t id2=fork();
if(id2==)
{
close();
dup(fd[]);
close(fd[]);
close(fd[]);
execvp(my_argv[],my_argv);
}
else
{
waitpid(id2,NULL,);
close();
dup(fd[]);
close(fd[]);
close(fd[]);
BuildCommand(my_argv,buf);
execvp(my_argv[],my_argv);
}

模拟Linux的shell的更多相关文章

  1. 在Window平台是模拟Linux的Shell环境

    在Linux平台模拟Linux的shell环境,可以通过一个软件实现:Cygwin(点击进入官网下载好即可),如下图(选择对应的版本进行下载): 安装: 1. 双击运行下载的安装包(选择从网络安装), ...

  2. Linux Bash Shell 快速入门

    BASH 的基本语法 最简单的例子 —— Hello World! 关于输入.输出和错误输出 BASH 中对变量的规定(与 C 语言的异同) BASH 中的基本流程控制语法 函数的使用 2.1     ...

  3. linux BASH shell设置字体与背景颜色

    linux BASH shell下设置字体及背景颜色的方法. BASH shell下设置字体及背景颜色  echo -e "\e[31mtest\e[41m"  \e[30m 将字 ...

  4. Linux Bash Shell入门教程

    Linux 系统根据 "#!" 及该字串后面的信息确定该文件的类型,关于这一问题同学们回去以后可以通过 "man magic"命令 及 /usr/share/m ...

  5. Windows上模拟Linux环境的软件Cygwin

    Windows上模拟Linux环境的软件Cygwin 2010-10-11 15:19      我要评论(0) 字号:T|T Cygwin是一个用于在Windows上 模拟Linux环境的软件.它可 ...

  6. “windows的批处理”与“Linux的shell script”的类比学习

    从2005年开始,做了将近10年的系统维护,先是做网络接入管理,然后做网络安全与审计,然后做服务器管理等整个网络系统的运营管理:现在又兼着做一些Linux下的视频监控系统的软硬件维护.过程中遇到太多重 ...

  7. Linux Bash Shell j简单入门

    BASH 的基本语法 最简单的例子 —— Hello World! 关于输入.输出和错误输出 BASH 中对变量的规定(与 C 语言的异同) BASH 中的基本流程控制语法 函数的使用 2.1     ...

  8. 详解Linux交互式shell脚本中创建对话框实例教程_linux服务器

    本教程我们通过实现来讲讲Linux交互式shell脚本中创建各种各样对话框,对话框在Linux中可以友好的提示操作者,感兴趣的朋友可以参考学习一下. 当你在终端环境下安装新的软件时,你可以经常看到信息 ...

  9. linux中shell变量$#,$@,$0,$1,$2的含义解释

    linux中shell变量$#,$@,$0,$1,$2的含义解释: 变量说明: $$ Shell本身的PID(ProcessID) $! Shell最后运行的后台Process的PID $? 最后运行 ...

随机推荐

  1. html5 canvas simple drawing

    var c = canvas.getContext("2d");//get canvas 2d context canvas including a proposed 3D con ...

  2. pl/sql和sql的区别

    源地址:https://zhidao.baidu.com/question/187511430.html 1 sql(数据定义语言) 和PL/Sql的区别:答:SQL是结构化查询语言,比较接近自然语言 ...

  3. (String)151. Reverse Words in a String

    Given an input string, reverse the string word by word. For example,Given s = "the sky is blue& ...

  4. DATAGUARD 在线重建备库

    环境: OS: CentOS 6.5 X64 DB: oracle 10.2.0.5 故障:之前由于错误激活备库主写导致主备日志同步,重建备库 1.关闭备库,删除数据文件及控制文件,redo文件 rm ...

  5. Bootstrap 4 中 Alerts 实现

    Alert 的使用说明 http://v4-alpha.getbootstrap.com/components/alerts/ JavaScript behavior Triggers Enable ...

  6. 全局修改Lable/Button字体

    本次版本需求要把原来的字体全改掉,由于项目中有的是代码创建的,有的是XIB中直接改的,一个一个改工作量太大,使用运行时可以很轻松的实现        首先,项目中大多数设置字体的控件有 Lable, ...

  7. 8,SFDC 管理员篇 - 数据模型 - 公式和验证 2

    1, Checkbox 只接受真值或者假值 And(arg1, arg2....)至少两个参数,只有参数都为真时候,才返回真,只要有一个为假,就都为假 例如:AND(DoNotCall, HasOpt ...

  8. Qlik 函数说明

    集合表达式 包括 标识符 标识符 说明 1 表示应用程序中所有记录的完整集合,而不考虑选择的任何选择项.考虑维度 $ 表示当前选择项的记录.因此,集合表达式 {$} 与不陈述集合表达式的意义等同. $ ...

  9. 百度地图API示例之移动地图

    级别为6 级别为8 级别为12 代码: <!DOCTYPE html> <html> <head> <meta http-equiv="Conten ...

  10. 9.S5PV210的时钟系统

    1.时钟域:MSYS.DSYS.PSYS(1)因为S5PV210的时钟体系比较复杂,内部外设模块太多,因此把整个内部的时钟划分为3大块,叫做3个域.(2)MSYS: CPU(Cortex-A8内核). ...