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\n");
    execvp("ls",arglist);
    printf("cmd done\n");
}

輸出:

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\n");

    fork();

    sleep(1);
        
    printf("finished!\n");
}    

  輸出:

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\n");
        execvp("ls",arglist);
    }
    else
    {
        printf("I'm the old process\n");
    }
}    

  輸出:

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\n"); execvp("ls",arglist); } else { wait(NULL); printf("I'm the old process\n"); } }

  輸出:

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()來返回一個退出的狀態。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM