实现mybash

20165212实现mybash

要求

  • 使用fork,exec,wait实现mybash
  • 写出伪代码,产品代码和测试代码
  • 发表知识理解,实现过程和问题解决的博客(包含代码托管链接)

学习相关知识

fork函数

查看帮助文档可以知道fork函数的头文件,函数原型,以及函数的功能等,如下图

  • fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
  • 一个进程调用fork()函数后,系统先给新的进程分配资源。
  • fork调用一次,却能够返回两次,它可能有三种不同的返回值。
    • 在父进程中,fork返回新创建子进程的进程ID;
    • 在子进程中,fork返回0;
    • 如果出现错误,fork返回一个负值。

我们可以通过fork返回的值来判断当前进程是子进程还是父进程。

源代码:

#include <unistd.h>  
#include <stdio.h>   
int main ()   
{   
pid_t fpid; //fpid表示fork函数返回的值  
int count=0;  
fpid=fork();   
if (fpid < 0)   
printf("error in fork!");   
else if (fpid == 0) {  
printf("i am the child process, my process id is %d\n",getpid());   
printf("我是子进程\n");//  
count++;  
}  
else {  
printf("i am the parent process, my process id is %d\n",getpid());   
printf("我是父进程\n");  
count++;  
}  
printf("统计结果是: %d\n",count);  
return 0;  
}  

 

问题:为什么count值没有受到影响呢? 解决:因为在创建了新进程之后,所有变量都存在不同的地址中,不是共用的,所有各有各的增减变化,互不影响。

exec函数族

- exec函数族提供了一个在进程中启动另一个程序执行的方法。 - 以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段。 - 可执行文件既可以是二进制文件,也可以是Linux下任何可执行脚本文件。 - 在该函数族中使用execl、execv、execlp、execvp函数使执行码重生时,Shell进程会将所有环境变量复制给生成的新进程;而使用execle、execve时新进程不继承任何Shell进程的环境变量,而由envp[]数组自行设置环境变量。

ls源代码

#include<unistd.h>
main()
{
char *argv[ ]={"ls", NULL};
char *envp[ ]={"PATH=/bin", NULL};
execve("/bin/ls", argv, envp);
}

 

运行结果

wait函数 wait()会暂时停止现在进程的执行,直到有信号来到或子进程结束。假如在调用wait()时子进程已结束,则wait()会立即返回子进程结束状态值。 waitpid提供了一个 wait的非阻塞版本,有时希望取得一个子进程的状态, 但不想进程阻塞。 mybash实现 伪代码:

while(1)
{
输出用户的ID,等数据;  
用户输入命令;  
将命令分割;
调用fork;
调用exec函数;
}

 

源代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>
#include <sys/wait.h>
#define N 100
#define order_length 128
#define order_num 64
#define empty 0
#define chars 1
void main()
{ 
   while(1) {
struct passwd *my_info;
char path[N];
my_info = getpwuid(getuid());
getcwd(path, sizeof(path));
printf("[%s@%s]$ ", my_info->pw_name, path);

char str[N];
char a[N];
char *argv[N]={NULL};
char *envp[]={0,NULL};
int i,j = 0, flag=1;
fgets(str,N,stdin);
str[N - 1] = '\0';
if(feof(stdin))
{
printf("error");
exit(0);
}
for(i=0;str[i]!='\0'&&i<N&&j<N;i++) {
if(str[i] == ' ' || str[i] == '\n') {
  flag=1;
  str[i] = '\0';
  }
  else if(flag==1) {
  argv[j++] = &str[i];
  flag=0;
  }
 }
 if(fork() != 0) wait(NULL);
else {
execvp(argv[0], argv);
perror("execlp error");
exit(0);
 }
 }
}

 

实验结果:


实验感想

上课的时候认真看老师演示了fork函数和execute函数,登堂入室;课下参考了不少学长学姐的博客,进一步复习fork函数和execute,实现了mybash,课余时间我会继续学习时间fork函数和execute函数,增加mybash的功能

posted @ 2018-11-25 20:52  FenixRen  阅读(275)  评论(0编辑  收藏  举报
#back-to-top { background-color:wheat; bottom: 0; box-shadow: 0 0 6px ; color: #444444; padding: 2px 2px; position: fixed; right: 20px; cursor: pointer; ヾ(≧O≦)〃嗷~ }