基于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 ...
随机推荐
- myeclipse 2013破解注册图文教程
以下这个试过有效 http://www.33lc.com/article/10792.html
- Java.util 包(Date 类、Calendar类、Random类)
java.util 包提供了一些实用的方法和数据结构. Date 类 Date 类表示日期和时间,里面封装了操作日期和时间的方法.Date 类经常用来获取系统当前时间. 构造方法: 构造方法 说明 D ...
- myeclipse run按钮不见了
window-->new window,打开新窗口,按钮出现了.关闭老窗口,再关闭新窗口.再次打开MyEclipse,妥妥的了.
- #npm install# MSBUILD : error MSB4132: 无法识别工具版本“2.0”。可用的工具版本为 "4.0"。
0.问题描述 Windows 10 最近使用npm install安装项目依赖包,当自动执行至node-gyp rebuild时报错: C:\Users\dsl\Desktop\Pros\ant-de ...
- 使用python 操作liunx的svn,方案二
在对liunx操作svn的方式,做了改动,使用python的,subprocess进行操作 在第一种方案中,我使用了先拉到本地,然后再创建,在进行上传,实际在svn中可以直接创建文件,并进行文件复制, ...
- swift动态库与use_frameworks
使用Dynamic 的优势: 模块化,相对于Static Library,Framework可以将模块中的函数代码外的资源文件打包在一起. 共享可执行文件 iOS 有沙箱机制,不能跨App间共享共态库 ...
- [19/04/22-星期一] GOF23_创建型模式(单例模式)
一.概念 <Design Patterns: Elements of Reusable Object-Oriented Software>(即后述<设计模式>一书),由 Eri ...
- wfst讲解
一.比较好的博客 1.0 官方网站 1.1 语音识别解码器(1)—自动机与半环 1.2 走进语音识别中的WFST 1.3Kaldi WFST 构图 学习 二.比较好的paper 三.开源项目 3.1 ...
- 软工之404 Note Found团队
如果记忆是一个罐头的话,我希望这一罐罐头不会过期----<重庆森林> 404 Note Found Team 如果记忆是一个备忘录的话,别说了,它不会过期----<404 Note ...
- Linux文本处理
作为一名 Linux 研发人员,几乎每天都要面对文本处理场景. 因此 掌握文本处理套路 并 熟练运用文本处理命令 ,对于 提升工作效率 意义重大. 本文以一个实战例子抛砖引玉,介绍如何运用 grep ...