对于system这个函数的功能早就有一定了解,读书期间,就学习了UNIX系统编程这本书,后来买了APUE.我这个人总是有好读书不求甚解的毛病。对于system函数只知其一,不知其二。后来被人问起相关的问题,结果丢了脸。书到用时方恨自己不求甚解。今天仔细探查了下system的一些特性。

 
    APUE这本书,对system这个函数已经将的比较明白了,只是它的相关知识稍显分散。最开始我是去网上找的资料,自己写的测试代码,可是还是有很多迷惑的地方。后来才拿起APUE ,好好读了第八章和第十章的相关章节。
 
    
  1. #include <stdlib.h>
  2. int system(const char *command);
    system的作用是在shell终端执行command。简单的说就是在C中执行system("ls")这行代码的含义就相当于在shell执行ls一样。这么说还是比较笼统,下面详细描述之:
 
    system是个综合的操作,分解开来看就是相当于执行了
1 fork  生成一个子进程。
2 在子进程执行 execl("/bin/sh","sh","-c" command,(char*)0);
3 waitpid
 
下面进入正题,返回值:
1 如果fork失败了,或者waitpid返回除了EINTR之外的错误,system返回 -1;
2 execl执行失败,其返回值如同shell执行了"exit(127)" 一样。
3 如果上述三步都执行成功,那么,system返回值是shell的终止状态。
 
 
上面这些话是APUE的,很抽象,很不具体,很笼统,我现在结合手册和代码解释一下。
 
手册中有这么一段话:
  1. The value returned is -1 on error (e.g.  fork(2) failed), and the return status of  the  command  otherwise.   This  latter  return  status  is in the format specified in wait(2).  Thus, the exit code of the command will be WEXITSTATUS(status).  In case /bin/sh could not be executed, the exit status will be that of a command that does
  2. exit(127).
1 如果/bin/sh拉起shell命令失败,或者是shell命令没有正常执行 (比如命令根本就是非法的命令),那么,将原因填入status的8~15位。
  手册中也说如果命令执行不起来,那么相当于执行exit
  1. libin@libin:~/program/C/Linux/system$ ./tsys "nosuchcmd"
  2. sh: nosuchcmd: not found
  3. status = 32512
  4. normal termination,exit status = 127
我们看到了,nosuchcmd不是shell支持的命令,所以,shell命令返回了127,对于system函数,返回值为127*256 = 32512;因为shell的返回值是 system返回值的8~15位。
 
2  如果shell顺利执行完毕,那么将shell的返回值填到system返回值的8~15位。
 这里需要强调以下,所谓顺利执行完毕,并不是说,命令command执行成功,而是指  /bin/sh顺利调用,执行期间没有被信号异常终止,这都算是顺利执行完毕。
  
看下面的例子:
 
  1. libin@libin:~/program/C/Linux/system$ ./tsys "ls /noexisted"
  2. ls: 无法访问/noexisted: 没有那个文件或目录
  3. status = 512
  4. normal termination,exit status = 2
  5. libin@libin:~/program/C/Linux/system$ ls /noexist
  6. ls: 无法访问/noexist: 没有那个文件或目录
  7. libin@libin:~/program/C/Linux/system$ echo $?
  8. 2
  9. libin@libin:~/program/C/Linux/system$
    我们看到了,虽然/noexist文件并不存在,ls这条命令执行出了错,但是仍然属于shell顺利执行完毕。ls /noexist的错误吗是2,所以,system函数的返回值为 2*256 = 512.
 
    各位可能比较感兴趣的是,如果我知道system的返回值,如何知道我的命令的返回值呢?手册中有这么一句话:
  1. Thus, the exit code of the command will be WEXITSTATUS(status)
    看到了WEXITSTATUS(status),就是command的返回值。当然前提条件是shell命令顺利执行完毕。即:
  1. WIFEXITED(status) ! =0
 
3 前面的讨论都没有考虑信号,如果shell在执行过程中收到了信号。
这个问题我存在有疑惑,因为APUE第十章讲到,system的实现要忽略SIGINT和SIGQUIT,但是我的实验结果并不是这样,如有高手知道,请不吝赐教。
 
首先看我的终端信号配置:
  1. libin@libin:~/program/C/Linux/system$ stty -a
  2. speed 38400 baud; rows 36; columns 134; line = 0;
  3. intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?; swtch = M-^?; start = ^Q; stop = ^S; susp = ^Z;
  4. rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
  5. -parenb -parodd cs8 hupcl -cstopb cread -clocal -crtscts
  6. -ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc ixany imaxbel iutf8
  7. opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
  8. isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
    Ctrl+C产生SIGINT,Ctrl+\ 产生 SIGQUIT。
    看下测试结果:
  1. libin@libin:~/program/C/Linux/system$ ./tsys "sleep 7"
  2. ^Cstatus = 2
  3. abnormal termination,signal number =2
  4. libin@libin:~/program/C/Linux/system$ sleep 7
  5. ^C
  6. libin@libin:~/program/C/Linux/system$ echo $?
  7. 130
    我们可以看到,直接在终端执行sleep 7,然后用Ctrl+C发送SIGINT信号,异常退出,shell返回值为130,130的原因,APUE上解释了,因为SIGINT 等于2,终止状态是128+信号编号,所以为130.
 
    按照APUE上,我们的system调用应该将SIGINT忽略掉,然后正常返回,同时返回值为130,但是实际上LINUX下并不是这样的。实际上system的返回值为2,并且异常退出了。
 
    SIGQUIT信号也是一样的,看我在我的Ubuntu 上做的测试:
  1. libin@libin:~/program/C/Linux/system$ ./tsys "sleep 7"
  2. ^\status = 3
  3. abnormal termination,signal number =3
  4. libin@libin:~/program/C/Linux/system$ sleep 7
  5. ^\退出
  6. libin@libin:~/program/C/Linux/system$ echo $?
  7. 131
 
    2012年1月1日,我做了下面的实验测试,下面是实验的过程。
  1. root@libin:~/program/C/Linux/system# ./tsys  "sleep 50" &
  2. [1] 2518
  3. root@libin:~/program/C/Linux/system# ps -ef
  4. root      2359  2343  0 12:42 pts/0    00:00:00 /bin/bash
  5. root      2518  2359  0 12:55 pts/0    00:00:00 ./tsys sleep 50
  6. root      2519  2518  0 12:55 pts/0    00:00:00 sh -c sleep 50
  7. root      2520  2519  0 12:55 pts/0    00:00:00 sleep 50
  8. root      2521  2359  0 12:56 pts/0    00:00:00 ps -ef
  9. root@libin:~/program/C/Linux/system# kill -3 2520
  10. Quit
  11. status = 33536
  12. normal termination,exit status = 131
  13. root@libin:~/program/C/Linux/system# ./tsys  "sleep 50" &
  14. [1] 2568
  15. root@libin:~/program/C/Linux/system# ps -ef
  16. root      2568  2359  0 13:01 pts/0    00:00:00 ./tsys sleep 50
  17. root      2569  2568  0 13:01 pts/0    00:00:00 sh -c sleep 50
  18. root      2570  2569  0 13:01 pts/0    00:00:00 sleep 50
  19. root      2571  2359  0 13:01 pts/0    00:00:00 ps -ef
  20. root@libin:~/program/C/Linux/system# kill -3 2569
  21. status = 3
  22. abnormal termination,signal number =3
 
    从测试结果上看,基本上进程关系如下,system的返回值,其实是shell的终止状态,
而不是sleep的返回值。所谓屏蔽INTR信号和QUIT信号,指的是tsys这个进程,忽略了INT信号的QUIT信号,但是sh进程,和sleep进程,都没有忽略这两个信号。
 
    如果给sleep进程发送SIGQUIT信号,杀死sleep进程,那么sleep会返回131,告诉shell进程我被SIGQUIT杀死了。而sh进程,则是安然退出,所以,依然打印出正常退出的打印,通过调用WEXITSTATUS,看以看出,sleep进程的遗言是131,表明收到QUIT信号。
 
 
    下面是测试程序,基本是照抄的APUE。
  1. #define _XOPEN_SOURCE
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include<unistd.h>
  5. #include<signal.h>
  6. #include<sys/wait.h>
  7. void pr_exit(int status)
  8. {
  9. printf("status = %d\n",status);
  10. if(WIFEXITED(status))
  11. {
  12. printf("normal termination,exit status = %d\n",WEXITSTATUS(status));
  13. }
  14. else if(WIFSIGNALED(status))
  15. {
  16. printf("abnormal termination,signal number =%d%s\n",
  17. WTERMSIG(status),
  18. #ifdef WCOREDUMP
  19. WCOREDUMP(status)?"core file generated" : "");
  20. #else
  21. "");
  22. #endif
  23. }
  24. }
  25. int main(int argc,char* argv[])
  26. {
  27. int status;
  28. if(argc<2)
  29. {
  30. fprintf(stderr,"usage:tsys cmd\n");
  31. return -1;
  32. }
  33. if((status = system(argv[1]) )<0)
  34. {
  35. fprintf(stderr,"system error\n");
  36. return -2;
  37. }
  38. pr_exit(status);
  39. return 0;
  40. }
十分感谢Heartwork的回复,本应该及早致谢,但是由于本周加班太多,机会每天都是10点以后到家,所以没有时间细细揣摩Heartwork的恢复。
 
参考文献:
1 APUE 

[转]system函数返回值探究的更多相关文章

  1. Linux system函数返回值

    例: status = system("./test.sh"); 1.先统一两个说法: (1)system返回值:指调用system函数后的返回值,比如上例中status为syst ...

  2. C语言:将3*4矩阵中找出行最大,列最小的那个元素。-将低于平均值的人数作为函数返回值,将低于平均分的分数放入below数组中。

    //将3*4矩阵中找出行最大,列最小的那个元素. #include <stdio.h> #define M 3 #define N 4 void fun(int (*a)[N]) { ,j ...

  3. 【C/C++】引用&的含义/语法/作为函数参数/函数返回值/本质/常量引用

    含义 引用不产生副本,只是给原变量起了别名. 对引用变量的操作就是对原变量的操作. 基本语法 数据类型 &别名 = 原名 e.g. int a = 10; int &b = a; // ...

  4. shell调用函数返回值深入分析

    编写shell脚本过程中,我们经常会自定义一些函数,并根据函数的返回值不同来执行相应的流程,那么我们如何来获取函数的返回值呢? 首先shell中调用函数有两种方式: 第一种:value=`functi ...

  5. Python从线程获取函数返回值

    Python中利用强大的threading模块可以很容易的实现多线程开发,提高运行速度.这一般是对某个进行大量计算操作的的函数进行多线程处理,然后合并各线程的结果.获取函数返回值的方法可以如下: 1) ...

  6. 速战速决 (3) - PHP: 函数基础, 函数参数, 函数返回值, 可变函数, 匿名函数, 闭包函数, 回调函数

    [源码下载] 速战速决 (3) - PHP: 函数基础, 函数参数, 函数返回值, 可变函数, 匿名函数, 闭包函数, 回调函数 作者:webabcd 介绍速战速决 之 PHP 函数基础 函数参数 函 ...

  7. string类find函数返回值判定

     string类find函数返回值判定 代码示例 #include<iostream> #include<cstring> using namespace std; int m ...

  8. c语言main函数返回值、参数详解(返回值是必须的,0表示正常退出)

    C语言Main函数返回值 main函数的返回值,用于说明程序的退出状态.如果返回0,则代表程序正常退出:返回其它数字的含义则由系统决定.通常,返回非零代表程序异常退出. 很多人甚至市面上的一些书籍,都 ...

  9. Python学习教程(learning Python)--2.3.4Python函数返回值

    本节讨论Python函数返回值问题. Python和C语言一样,也可以在函数结束时返回一个值.但在定义自己的Python函数时,是不需要指定返回值数据类型的,这和Python不关心变量的数据类型是一致 ...

随机推荐

  1. Android必会小功能总结

    1.获取屏幕尺寸.密度等信息. 1)最常用的方法: WindowManager windowManager = getWindowManager(); Display display = window ...

  2. 程序编码(机器级代码+汇编代码+C代码+反汇编)

    [-1]相关声明 本文总结于csapp: 了解详情,或有兴趣,建议看原版书籍: [0]程序编码 GCC调用了一系列程序,将源代码转化成可执行代码的流程如下: (1)C预处理器扩展源代码,插入所有用#i ...

  3. Oracle数据库查看执行计划

    基于ORACLE的应用系统很多性能问题,是由应用系统SQL性能低劣引起的,所以,SQL的性能优化很重要,分析与优化SQL的性能我们一般通过查看该SQL的执行计划,本文就如何看懂执行计划,以及如何通过分 ...

  4. 20145102 《Java程序设计》第1周学习总结

    20145102 <Java程序设计>第1周学习总结 教材学习内容总结 linux下对于java的安装是非常简便的,只要参照ArchWiki就可以快速安装,没有Windows上那么复杂.I ...

  5. C语言数据类型

    1.概述 C 语言包含的数据类型如下图所示: 2.各种数据类型介绍 2.1整型 整形包括短整型.整形和长整形. 2.1.1短整形 short a=1; 2.1.2整形 一般占4个字节(32位),最高位 ...

  6. 如何在mac上安装composer(How to install composer on the Mac)

    Change into a directory in your path like cd /usr/local/bin Get Composer curl -sS https://getcompose ...

  7. html使用空格对齐文本(&nbsp;&emsp;&ensp;)

    字符以及HTML实体 描述以及说明   这是我们使用最多的空格,也就是按下space键产生的空格.在HTML中,如果你用空格键产生此空格,空格是不会累加的(只算1个).要使用html实体表示才可累加. ...

  8. 自定义input file 属性

    <label class="input"><input title="浏览文件" type="file" />浏览… ...

  9. Echarts 使用遇到的问题

    1.在使用ECharts的数据视图时,单击打开数据视图如下,当单击close按钮时,如果当前图像区域包含在一个<from></from>标签中,则会刷整个新页面, 去掉< ...

  10. js标签放在html的什么位置比较好

    推荐的是js的script标签放在body的末尾,</body>标签之前,包含在body内! <body> <!--其它Html标签--> <script&g ...