zoukankan      html  css  js  c++  java
  • UNIX-LINUX编程实践教程->第八章->实例代码注解->写一个简单的shell->在shell中启动另一个程序

    一 分析

      shell启动一个程序,包括以下几步:

      1)从用户读入指令字符串
      2)shell建立一个新进程
      3)在新进程中运行指令并等待进程结束

      用户如何读入指令我们就不在此探讨了,这里主要探讨如何在一个程序里启动另一个程序。

    二 一个程序如何运行另一个程序

    1 使用execvp函数来启动另一个程序

      execvp()函数
      找到指定路径的文件并执行该文件
      头文件:#include<unistd.h>
      函数原型:int execvp(const char *file ,char * const argv []);
      参数:  file    可执行文件的路径+文件名
           argv   参数组
      返回值: 若函数执行成功则不会返回,若执行失败就直接返回-1

     代码示意:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main()
    {
        char* arglist[3];
    
        arglist[0] = "ls";
        arglist[1] = "-l";
        arglist[2] = 0;    
    
        printf("ready for cmd ls
    ");
        execvp("ls",arglist);
        printf("cmd done
    ");
    }

    输出:

    ready for cmd ls
    total 44
    -rwxrwxr-x 1 lqx lqx 7196 2013-06-17 09:17 a.out
    -rw-rw-r-- 1 lqx lqx  497 2013-04-25 15:12 execute.c
    -rw-rw-r-- 1 lqx lqx  482 2013-04-23 15:54 psh2.c
    -rw-rw-r-- 1 lqx lqx  584 2013-04-25 15:10 smsh1.c
    -rw-rw-r-- 1 lqx lqx  202 2013-04-25 15:14 smsh.h
    -rw-rw-r-- 1 lqx lqx 1715 2013-04-25 15:13 splitline.c
    -rw-rw-r-- 1 lqx lqx  241 2013-06-17 09:16 test.c
    -rwxrwxr-x 1 lqx lqx 7310 2013-05-09 14:46 testline
    -rw-rw-r-- 1 lqx lqx  436 2013-05-10 14:46 testline.c

      在上面的代码中,执行了“ls -l”,需要注意的是,arglist[2]=0表示指令结束。最后有个奇怪的地方,“cmd done”似乎没有被打印出来?这是因为调用execvp后,新的进程覆盖了原有的进程,新进程结束后并不会返回老进程而是直接结束。解决办法是在老进程里新建一个进程,在新的进程里调用execvp,这样就能防止老进程后续的指令无法执行。

    2 使用fork函数来复制进程

      fork()函数
      当一个进程调用fork后,就有两个代码相同的进程,而且它们都运行到相同的位置。
      头文件:#include<unistd.h>  #include<sys/types.h>
      函数原型:pid_t fork(void);
      参数:无
      返回值:若成功调用,子进程返回0,父进程返回子进程ID;否则出错返回-1

       代码示意:

    int main()
    {
        printf("ready to fork
    ");
    
        fork();
    
        sleep(1);
            
        printf("finished!
    ");
    }    

      输出:

    lqx@lqx-virtual-machine:~/bin/UnixPrograme/8$ ./a.out
    ready to fork
    finished!
    lqx@lqx-virtual-machine:~/bin/UnixPrograme/8$ finished!

      从上面可以看出,进程在执行fork后输出了两次“finished”,原因就是fork创建的进程与原进程是一样的且同样执行到fork函数返回的地方,于是“finished”在两个进程中分别被输出。

    3 使用新进程来启动另一个程序

      在上面,我们使用fork新创建了一个跟原进程一样的新进程,我们可以在新的进程里来启动需要的程序,但我们也知道,新进程与旧的进程是一样的,那么进程如何知道自己是新的还是老的呢?我们可以利用fork的返回值来判断,子进程的fork返回0,父进程的fork返回子进程ID。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    
    
    int main()
    {
        char* arglist[3];
        int i;
    
        arglist[0] = "ls";
        arglist[1] = "-l";
        arglist[2] = 0;    
    
        i = fork();
        if(i==0)
        {
            printf("I'm the new process.ready for cmd ls
    ");
            execvp("ls",arglist);
        }
        else
        {
            printf("I'm the old process
    ");
        }
    }    

      输出:

    lqx@lqx-virtual-machine:~/bin/UnixPrograme/8$ ./a.out
    I'm the old process
    lqx@lqx-virtual-machine:~/bin/UnixPrograme/8$ I'm the new process.ready for cmd
    ls
    total 44
    -rwxrwxr-x 1 lqx lqx 7232 2013-06-19 09:51 a.out
    -rw-rw-r-- 1 lqx lqx  497 2013-04-25 15:12 execute.c
    -rw-rw-r-- 1 lqx lqx  482 2013-04-23 15:54 psh2.c
    -rw-rw-r-- 1 lqx lqx  584 2013-04-25 15:10 smsh1.c
    -rw-rw-r-- 1 lqx lqx  202 2013-04-25 15:14 smsh.h
    -rw-rw-r-- 1 lqx lqx 1715 2013-04-25 15:13 splitline.c
    -rw-rw-r-- 1 lqx lqx  379 2013-06-19 09:51 test.c
    -rwxrwxr-x 1 lqx lqx 7310 2013-05-09 14:46 testline
    -rw-rw-r-- 1 lqx lqx  436 2013-05-10 14:46 testline.c

      输出里可以看到,新老进程都执行完毕。到这里还并不完美,因为在很多应用场景中,旧的进程需要等待新进程执行完毕了再进行下一步的操作,

     4 父进程使用wait函数来等待子进程返回

      wait()函数
      进程调用wait后立即阻塞自己,直到其子进程返回
      头文件:无
      函数原型:pid_t wait (int* status)
      参数:status 保存子进程退出时的状态信息
      返回值:成功则返回子进程ID,若该进程没有子进程则返回-1

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    int main() { char* arglist[3]; int i; arglist[0] = "ls"; arglist[1] = "-l"; arglist[2] = 0; i = fork(); if(i==0) { printf("I'm the new process.ready for cmd ls "); execvp("ls",arglist); } else { wait(NULL); printf("I'm the old process "); } }

      输出:

    lqx@lqx-virtual-machine:~/bin/UnixPrograme/8$ ./a.out
    I'm the new process.ready for cmd ls
    total 44
    -rwxrwxr-x 1 lqx lqx 7268 2013-06-19 10:26 a.out
    -rw-rw-r-- 1 lqx lqx  497 2013-04-25 15:12 execute.c
    -rw-rw-r-- 1 lqx lqx  482 2013-04-23 15:54 psh2.c
    -rw-rw-r-- 1 lqx lqx  584 2013-04-25 15:10 smsh1.c
    -rw-rw-r-- 1 lqx lqx  202 2013-04-25 15:14 smsh.h
    -rw-rw-r-- 1 lqx lqx 1715 2013-04-25 15:13 splitline.c
    -rw-rw-r-- 1 lqx lqx  389 2013-06-19 10:26 test.c
    -rwxrwxr-x 1 lqx lqx 7310 2013-05-09 14:46 testline
    -rw-rw-r-- 1 lqx lqx  436 2013-05-10 14:46 testline.c
    I'm the old process

      这里,子进程没有用到exit()来返回一个退出的状态。

  • 相关阅读:
    Spring Bean Scope 有状态的Bean 无状态的Bean
    管理Mysql常用指令
    mysql处理特殊字符
    linux下memcached安装 和redis安装,jdk,tomcat,mysql 安装
    Jenkins
    tomcat站点配置
    tomcat配置jdbc
    spring 深入reading
    JAVA随机数之多种方法从给定范围内随机N个不重复数
    Intellij IDEA 快捷键整理
  • 原文地址:https://www.cnblogs.com/cation/p/3135940.html
Copyright © 2011-2022 走看看