基于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的更多相关文章

  1. Linux下的bash对拍

    下面是Linux下的bash对拍程序: #!/bin/bash t=0 //数据组数 while true; do let "t=$t + 1" echox printf $t / ...

  2. 【转】基于Qt, TUIO和TSLIB的嵌入式Linux下的多点触摸设计

    这个教程描述了在嵌入式linux下使用Qt如何设置一个支持多点触摸和单点触摸的输入系统.这里假定你已经有了对应的驱动程序,驱动可以从触摸屏的厂商那里获得或者使用一个linux 内核源码中已经存在的驱动 ...

  3. linux下提示bash:command not found

    新安装的linux系统,如果进行精简安装可能会出现bash:command not found 的提示,大家在安装的时候可以选择默认安装basic的组件,一般即可.到时候可以再升级.   如果新装的系 ...

  4. Linux下sh/bash/source/.命令的区别(转)

    一..sh文件介绍 .sh为Linux的脚本文件,我们可以通过.sh执行一些命令,可以理解为windows的.bat批处理文件. 二.点命令(.) .命令和source是同一个命令,可以理解为sour ...

  5. Linux下用Bash语言实现简单排序的功能

    题目链接: 题目描述 利用指针,编写一个函数实现三个整数按由小到大的排序. 输入 三个整数 输出 由小到大输出成一行,每个数字后面跟一个空格 样例输入 2 3 1 样例输出 1 2 3 复习下Linu ...

  6. Linux下用Bash语言实现输出水仙花数的功能

    题目链接: 题目描述 打印出所有"水仙花数",所谓"水仙花数"是指一个三位数,其各位数字立方和等于该本身. 例如:153是一个水仙花数,因为153=1^3+5^ ...

  7. Linux下用Bash语言实现输出最大值的功能

    题目链接: 题目描述 编写一个程序,输入a.b.c三个值,输出其中最大值. 输入 一行数组,分别为a b c 输出 a b c其中最大的数 样例输入 10 20 30 样例输出 30 复习下Linux ...

  8. Linux下用Bash语言实现判断素数的功能

    题目链接: 题目描述 写一个判断素数的函数,在主函数输入一个整数,输出是否是素数的消息. 输入 一个数 输出 如果是素数输出prime 如果不是输出not prime 样例输入 97 样例输出 pri ...

  9. Linux下运行bash脚本显示“: /usr/bin/env: "bash\r": 没有那个文件或目录

    用 ./ 运行bash脚本文件出现 报错信息 /usr/bin/env: "bash\r": 没有那个文件或目录 错误原因:这主要是因为bash后面多了\r这个字符的原因.在lin ...

随机推荐

  1. 数据库相关文章转载(2) MySQL自带的性能压力测试工具mysqlslap详解

    PS:今天一同事问我有木有比较靠谱的mysql压力测试工具可用.其实mysql自带就有一个叫mysqlslap的压力测试工具,还是模拟的不错的.下面举例说说.mysqlslap是从5.1.4版开始的一 ...

  2. kafka概要设计

    Kafka核心功能 即:高性能的消息发送与高性能的消息消费 下载安装包后即可启动Kafka服务器,但是此前需要首先启动Zookeeper服务器,Zookeeper是为Kafka提供协调服务的工具,Ka ...

  3. 前端构建之--gulp

    gulp相关插件: 1.del / gulp-clean 删除文件,用于清空文件 2.browser-sync 用于自动刷新浏览器 3.gulp-htmlmin 用于压缩html 4.gulp-cle ...

  4. 利用TLE数据确定卫星轨道(2)-SGP4模型实现

    1.TLE轨道报: 接上一篇,TLE轨道报各项内容所代表的意义如下: 2.SGP4模型: TLE轨道报计算卫星轨道需要用到 NORAD 开 发 的 SGP4/SDP4 模 型 ,SGP4模型是由 Ke ...

  5. FreeRTOS+ WolfSSL + Lwip Demo

    FreeRTOS+ WolfSSL Demo下载 LWIP 源码下载  2018年2月5日09:39:08 WolfSSL is about 10 times smaller than yaSSL, ...

  6. EF Core 中多次从数据库查询实体数据,DbContext跟踪实体的情况

    使用EF Core时,如果多次从数据库中查询一个表的同一行数据,DbContext中跟踪(track)的实体到底有几个呢?我们下面就分情况讨论下. 数据库 首先我们的数据库中有一个Person表,其建 ...

  7. 处理HTML表单(11)

    PHP和Web表单 <?php if(isset($_POST["name"])){//isset()函数设置变量是否设置,并且不能为空 $name = $_POST[&qu ...

  8. Set集合之HashSet类

    HashSet简介 HashSet是Set接口的典型实现,大多数时候使用Set集合时就是使用这个实现类.HashSet按Hash算法来存储集合中的元素,因此具有良好的存取和查找性能. HashSet特 ...

  9. PLSQL Developer 12 注册码

    PLSQL Developer 12 注册码product code: 4vkjwhfeh3ufnqnmpr9brvcuyujrx3n3le serial Number:226959 password ...

  10. c#采用emit将DataTable转List

    前面已经说了List转DataTable,也整理了代码. 现在转回来说说DataTable转List. 先举一个例子 public class Person { public int Age{get; ...