基于fork(),execvp()和wait()实现类linux下的bash——mybash
基于fork(),execvp()和wait()实现类linux下的bash——mybash
预备知识
- fork():fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事http://blog.csdn.net/jason314/article/details/5640969。
- 重点是后一句话,如果初始参数或者传入变量不同,两个进程也可以做不同的事,意思就是虽然父进利用fork()函数创造了一个和自己完全一致的子进程,但由于子进程执行指针开始至位于fork()函数后,意思就是子进程不会再执行一次fork()上面的代码,所有的fork()前定义的变量,都将保持初始化的值。
- wait():进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止,wait其实比较好理解http://blog.sina.com.cn/s/blog_759803690101aqeq.html。
- execvp():exec系统调用会从当前进程中把当前程序的机器指令清除,然后在空的进程中载入调用时指定的程序代码,最后运行这个新的程序http://www.linuxidc.com/Linux/2011-10/44527.htm.
- 这样的定义就意味着,所有execvp()后面的代码都将不被执行,相当于在主函数里“重写”了一遍传入execvp函数中的程序,又在紧接着在后面加了句exit(1);这样往往带来不便,但根据定义,我们可以将fork和execvp结合,从而保护父进程。
产品伪代码
Step1:读入用户输入的指令;
Step2:调用fork函数生成一个子进程,并将fork返回的pid值赋给fpid;
Step3:调用wait函数,传入null;
Step4:判断fpid是否为零,如果为零执行Step5;如果不为零,执行Step6;
Step5:调用execvp函数,并把用户输入的指令传进去;
Step6:返回Step1;
产品代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAXARGS 20
#define ARGLEN 100
int execute( char *arglist[] )
{
execvp(arglist[0], arglist);
perror("execvp failed");
exit(1);
}
char * makestring( char *buf )
{
char *cp;
buf[strlen(buf)-1] = '\0';
cp = malloc( strlen(buf)+1 );
if ( cp == NULL ){
fprintf(stderr,"no memory\n");
exit(1);
}
strcpy(cp, buf);
return cp;
}
int mybash(char *arglist[])
{
int flag=0;
flag=fork();
wait(NULL);
if(flag==0)
execute( arglist );
else return 1;
}
测试代码
#include<stdio.h>
#include <string.h>
#include"head.h"
int mybash(char *arglist[]);
int test1()
{
char *test1[10],*test2[10],*test3[10],*test4[10],*test5[10],*test6[10];
test1[0]="ls";
test1[1]="-l";
test1[2]=0;
test2[0]="od";
test2[1]="-tc";
test2[2]="-tx1";
test2[3]="12.txt";
test2[4]=0;
test3[0]="mkdir";
test3[1]="success";
test3[2]=0;
test4[0]="git";
test4[1]="add";
test4[2]=".";
test4[3]=0;
test5[0]="git";
test5[1]="commit";
test5[2]="-m";
test5[3]="\"test11\"";
test5[4]=0;
test6[0]="git";
test6[1]="push";
test6[2]="origin";
test6[3]="master";
test6[4]=0;
int flag=0;
if(flag=mybash(test1)==1)printf("\n%s %s test Success!\n",test1[0],test1[1]);
flag=0;
if(flag=mybash(test2)==1)printf("\n%s %s %s %s test Success!\n",test2[0],test2[1],test2[2],test2[3]);
flag=0;
if(flag=mybash(test3)==1)printf("\n%s %s test Success!\n",test3[0],test3[1]);
flag=0;
if(flag=mybash(test4)==1)printf("\n%s %s %s test Success!\n",test4[0],test4[1],test4[2]);
flag=0;
if(flag=mybash(test5)==1)printf("\n%s %s %s %s test Success!\n",test5[0],test5[1],test5[2],test5[3]);
flag=0;
if(flag=mybash(test6)==1)printf("\n%s %s %s %s test Success!\n",test6[0],test6[1],test6[2],test6[3]);
return 0;
}
- 测试运行截图

问题及解决方法
- 问题1:因为使用的是execvp函数是放在主函数里的,往往都会直接终结掉父进程,这是主要问题;
- 问题1解决:调用fork函数生成一个子进程,并且只允许execvp运行在子进程中,这样execvp终结掉的就只是子进程,而不会影响父进程,而对于fork函数完整复制父进程的子进程也会因为调用了execvp而及时终结掉,不会导致一个无谓的循环。
- 问题2:怎么实现只让execvp运行在子进程,而不去影响父进程
- 问题2解决:这是根本问题,解决了才能使得mybash正常的去运行去循环,因为fork函数的特性就是完整复制父进程,但子进程永远都是从fork后面执行意思就是,fork前面的变量将保持初始化的值,而不受fork前面的代码影响,所以,这里可以使用fpid来作为flag判断这是一个子进程还是一个父进程,如果是一个子进程那么就运行execvp,如果不是就返回继续执行父进程;
运行截图

码云链接
基于fork(),execvp()和wait()实现类linux下的bash——mybash的更多相关文章
- Linux下的bash对拍
下面是Linux下的bash对拍程序: #!/bin/bash t=0 //数据组数 while true; do let "t=$t + 1" echox printf $t / ...
- 【转】基于Qt, TUIO和TSLIB的嵌入式Linux下的多点触摸设计
这个教程描述了在嵌入式linux下使用Qt如何设置一个支持多点触摸和单点触摸的输入系统.这里假定你已经有了对应的驱动程序,驱动可以从触摸屏的厂商那里获得或者使用一个linux 内核源码中已经存在的驱动 ...
- linux下提示bash:command not found
新安装的linux系统,如果进行精简安装可能会出现bash:command not found 的提示,大家在安装的时候可以选择默认安装basic的组件,一般即可.到时候可以再升级. 如果新装的系 ...
- Linux下sh/bash/source/.命令的区别(转)
一..sh文件介绍 .sh为Linux的脚本文件,我们可以通过.sh执行一些命令,可以理解为windows的.bat批处理文件. 二.点命令(.) .命令和source是同一个命令,可以理解为sour ...
- Linux下用Bash语言实现简单排序的功能
题目链接: 题目描述 利用指针,编写一个函数实现三个整数按由小到大的排序. 输入 三个整数 输出 由小到大输出成一行,每个数字后面跟一个空格 样例输入 2 3 1 样例输出 1 2 3 复习下Linu ...
- Linux下用Bash语言实现输出水仙花数的功能
题目链接: 题目描述 打印出所有"水仙花数",所谓"水仙花数"是指一个三位数,其各位数字立方和等于该本身. 例如:153是一个水仙花数,因为153=1^3+5^ ...
- Linux下用Bash语言实现输出最大值的功能
题目链接: 题目描述 编写一个程序,输入a.b.c三个值,输出其中最大值. 输入 一行数组,分别为a b c 输出 a b c其中最大的数 样例输入 10 20 30 样例输出 30 复习下Linux ...
- Linux下用Bash语言实现判断素数的功能
题目链接: 题目描述 写一个判断素数的函数,在主函数输入一个整数,输出是否是素数的消息. 输入 一个数 输出 如果是素数输出prime 如果不是输出not prime 样例输入 97 样例输出 pri ...
- Linux下运行bash脚本显示“: /usr/bin/env: "bash\r": 没有那个文件或目录
用 ./ 运行bash脚本文件出现 报错信息 /usr/bin/env: "bash\r": 没有那个文件或目录 错误原因:这主要是因为bash后面多了\r这个字符的原因.在lin ...
随机推荐
- HTTP协议图--HTTP 协议基础
1.通过请求和响应的交换达成通信 应用 HTTP 协议时,必定是一端担任客户端角色,另一端担任服务器端角色.仅从一条通信线路来说,服务器端和客服端的角色是确定的.HTTP 协议规定,请求从客户端发出, ...
- 通用型正方教务(通杀各版本)存在注入(不需登陆)+获得webshell+提权内网漫游
某个接口页面存在oracle盲注,可以获得当前用户数据库,dump教师用户表,分析密文加密特征(前人研究成果+基友助攻),破译加密的密码.前台管理员登陆,后台文件上传基于黑名单原理,过滤u完全,上传特 ...
- 4、Node.js REPL(交互式解释器)
Node.js REPL(Read Eval Print Loop:交互式解释器) 表示一个电脑的环境,类似 Window 系统的终端或 Unix/Linux shell,我们可以在终端中输入命令,并 ...
- 【OpenCV】【MFC】图片、视频、摄像头输入响应【详细图解】
记住新建项目后,要配置OpenCV环境!参考链接http://blog.csdn.net/zy122121cs/article/details/49180541 做工程搭建框架什么的,基本的要熟练啊. ...
- Vuex、Flux、Redux、Redux-saga、Dva、MobX
https://www.jqhtml.com/23003.html 这篇文章试着聊明白这一堆看起来挺复杂的东西.在聊之前,大家要始终记得一句话:一切前端概念,都是纸老虎. 不管是Vue,还是 Reac ...
- BZOJ1259:[CQOI2007]矩形rect(DFS)
Description 给一个a*b矩形,由a*b个单位正方形组成.你需要沿着网格线把它分成分空的两部分,每部分所有格子连通,且至少有一个格子在原矩形的边界上.“连通”是指任两个格子都可以通过水平或者 ...
- Kali-linux使用NVIDIA计算机统一设备架构(CUDA)
CUDA(Compute Unified Device Architecture)是一种由NVIDIA推出的通用并行计算架构,该架构使用GPU能够解决复杂的计算问题.它包含了CUDA指令集架构(ISA ...
- Go并发与.Net TAP
Go package main import "fmt" func sum(arrays []int, ch chan int) { fmt.Println(arrays) sum ...
- 用Maven创建动态Web工程
前言 maven是一个强大的工具.如果你知道如何使用它,你只要付出最小的努力,但可以获得最大的回报.一般来说,maven可以帮助你管理项目,包括管理依赖库.构建工程等. 下面将通过一个简单的教程来描述 ...
- H5上传图片,并且显示进度条
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...