进程控制 简单myshell的实现

#include<unistd.h>
#include<sys/wait.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>


  void do_parse(char *buf,char* argv[])
{
    int i;
    int argc=0;
    int status=0;
   for(i=0;buf[i];i++)
   {
      if(  !isspace(buf[i])   &&   status==0)
      {
       argv[argc++]=buf+i;
       status=1;

      }else if( isspace(buf[i]) )
      {

        status=0;
        buf[i]='\0';

     }
   }
    argv[argc]=NULL;
}
void process_create(pid_t*pid,int func(const char*file,char*const argv[]),char*const argv[])
{
     int pid1=*pid; 
        switch(pid1)
        {
            case -1:
                perror("fork");
                exit(EXIT_FAILURE);
                break;
            case 0:
              //child
                func(argv[0],argv); 
                perror("process_create");
                 exit(EXIT_FAILURE);
                 break;
            default:
                 {//fater
                    int c;
                   while(wait(&c)!=pid1)
                  {
                        ;
                  }
                  break;
                 }        
         }

}
int main()
{
    char* argv[8];
    int argc = 0;
    char buf[1024]={0};

    while(1)
    {
        printf("[myshell~]");

        scanf("%[^\n]%*c",buf);
        
        do_parse(buf,argv);
        
        pid_t pid=fork();
       
        process_create(&pid,execvp,argv);

        memset(buf,0,1024);
    }
}

以上为myshell 的代码部分,系统调用的执行函数为execvp,可以正常运行ls、vim、gcc 等命令,

但不能运行  |  、 cd 、 >等命令。

对main函数中的 scanf (" %[^\n]  %*c" ,  buf)  进行解释:

%[ ]的意思为读取一个字符集  

%[^\n]的意思为 读取 \n前的所有字符

%*    *代表丢弃读取到的数据

%*c   表示丢到读取到底字符 (因为前面已经读取了\n前的数据,就剩下\n了,此句子中表示读取\n并丢弃它)。

总和的意思是将\n前的所有字符读取到buf中,将\n从缓冲区读取并丢弃。


关于system和popen与fork的区别:

fork 用来创建一个子进程 一个程序一调用fork函数,首先,系统让新的进程与旧的进程使用同一个代码段,因为它们的程序还是相同的,对于数据段和堆栈段,系统则复制一份给新的进程,这样,父进程的所有数据都可以留给子进程,但是,子进程一旦开始运行,虽然它继承了父进程的一切数据,但实际上数据却已经分开,相互之间不再有影响了,也就是说,它们之间不再共享任何数据了。而如果两个进程要共享什么数据的话,就要使用另一套函数(shmget,shmat,shmdt等)来操作。现在,已经是两个进程了,对于父进程,fork函数返回了子程序的进程号,而对于子程序,fork函数则返回零,这样,对于程序,只要判断fork函数的返回值,就知道自己是处于父进程还是子进程中。

 system 可以看做是fork + execl + waitpid。system()函数,功能强大 当system接受的命令为NULL时直接返回,否则fork出一个子进程,因为fork在两个进程:父进程和子进程中都返回,这里要检查返回的pid,fork在子进程中返回0,在父进程中返回子进程的pid,父进程使用waitpid等待子进程结束,子进程则是调用execl来启动一个程序代替自己,execl(“/bin/sh”, “sh”, “-c”, cmdstring, (char*)0)是调用shell,这个shell的路径是/bin/sh,后面的字符串都是参数,然后子进程就变成了一个shell进程,这个shell的参数是cmdstring,就是system接受的参数。在windows中的shell是command,想必大家很熟悉shell接受命令之后做的事了。

 popen()也常常被用来执行一个程序 

popen() 函数用创建管道的方式启动一个 进程, 并调用 shell. 因为管道是被定义成单向的, 所以 type 参数只能定义成只读或者只写, 不能是两者同时, 结果流也相应的是只读或者只写. command 参数是一个字符串指针, 指向的是一个以 null 结束符结尾的字符串, 这个字符串包含一个 shell 命令. 这个命令被送到 /bin/sh 以 -c 参数执行, 即由 shell 来执行. type 参数也是一个指向以 null 结束符结尾的字符串的指针, 这个字符串必须是 ‘r‘ 或者 ‘w’ 来指明是读还是写. 
popen() 函数的返回值是一个普通的标准I/O流, 它只能用 pclose() 函数来关闭, 而不是 fclose() 函数. 向这个流的写入被转化为对 command 命令的标准输入; 而 command 命令的标准输出则是和调用 popen(), 函数的进程相同,除非这个被command命令自己改变. 相反的, 读取一个 “被popen了的” 流, 就相当于读取 command 命令的标准输出, 而 command 的标准输入则是和调用 popen, 函数的进程相同.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值