[转]system函数返回值探究

对于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. [email protected]:~/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. [email protected]:~/program/C/Linux/system$ ./tsys "ls /noexisted"
  2. ls: 无法访问/noexisted: 没有那个文件或目录
  3. status = 512
  4. normal termination,exit status = 2
  5. [email protected]:~/program/C/Linux/system$ ls /noexist
  6. ls: 无法访问/noexist: 没有那个文件或目录
  7. [email protected]:~/program/C/Linux/system$ echo $?
  8. 2
  9. [email protected]:~/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. [email protected]:~/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. [email protected]:~/program/C/Linux/system$ ./tsys "sleep 7"
  2. ^Cstatus = 2
  3. abnormal termination,signal number =2
  4. [email protected]:~/program/C/Linux/system$ sleep 7
  5. ^C
  6. [email protected]:~/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. [email protected]:~/program/C/Linux/system$ ./tsys "sleep 7"
  2. ^\status = 3
  3. abnormal termination,signal number =3
  4. [email protected]:~/program/C/Linux/system$ sleep 7
  5. ^\退出
  6. [email protected]:~/program/C/Linux/system$ echo $?
  7. 131

2012年1月1日,我做了下面的实验测试,下面是实验的过程。

  1. [email protected]:~/program/C/Linux/system# ./tsys  "sleep 50" &
  2. [1] 2518
  3. [email protected]:~/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. [email protected]:~/program/C/Linux/system# kill -3 2520
  10. Quit
  11. status = 33536
  12. normal termination,exit status = 131
  13. [email protected]:~/program/C/Linux/system# ./tsys  "sleep 50" &
  14. [1] 2568
  15. [email protected]:~/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. [email protected]:~/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

时间: 2024-11-05 12:10:30

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

Linux system函数返回值

例: [cpp] view plain copy status = system("./test.sh"); 1.先统一两个说法: (1)system返回值:指调用system函数后的返回值,比如上例中status为system返回值 (2)shell返回值:指system所调用的shell命令的返回值,比如上例中,test.sh中返回的值为shell返回值. 2.如何正确判断test.sh是否正确执行? 仅判断status是否==0?或者仅判断status是否!=-1? 都错! 3.

linux编程中接收主函数返回值以及错误码提示

程序A创建子进程,并调用进程B,根据不调用的不同情况,最后显示结果不同. #include <stdio.h> #include <unistd.h> #include <sys/wait.h> #include <sys/types.h> #include <errno.h> int main() { pid_t pid, rpid; int stat; if ((pid = fork()) < 0) { perror("for

python中os.system()的返回值

最近遇到os.system()执行系统命令的情况,上网搜集了一下资料,整理如下,以备不时之需,同时也希望能帮到某些人. 一.python中的 os.system(cmd)的返回值与linux命令返回值(具体参见本文附加内容)的关系 大家都习惯用os.systemv()函数执行linux命令,该函数的返回值十进制数(分别对应一个16位的二进制数).该函数的返回值与 linux命令返回值两者的转换关系为:该函数的返回值(十进制)转化成16二进制数,截取其高八位(如果低位数是0的情况下,有关操作系统的

C语言中函数返回值的问题

c语言中有关于在函数返回值的问题,在函数中的局部变量主要是在栈上开辟的,出了函数变量就被回收了,针对函数返回值得问题,给出下面几个比较具体的例子来说明: 函数返回值是在函数中定义的局部变量 这类型的返回值在主函数中是可以使用的,因为返回局部变量值得时候,返回的是值得一个副本,而在主函数中我们需要的也只是这个值而已,因此是可以的,例如 int fun(char *arr) { int num = 0; while (*arr != '\\0') { num = num * 10 + *arr -

函数指针,函数指针数组,函数返回值为函数指针

函数的名字就是函数的首地址:定义函数指针; int (*p)(int ) p为函数指针变量名字,int 为函数的返回值类型为int型:(int)为函数的形参类型为int型, 注:因为优先级所以要用(*p),否则就会p先和后面的()结合为int*p(int),意思就变为p(int)函数的返回值为int* 注:main2()函数中   int (*p[])(int ,int )  为一维数组,下面写错了, #include<stdio.h> #include<stdlib.h> int

C基础--指针与函数返回值

#include <stdio.h> #define A 0 int funcA(int a, int b) { return a + b; } /*把指针作为函数的返回值*/ int * funcB(int a, int b) { static int c = A; c = a + b; return &c; } /*通过函数进行内存的申请*/ /* * 参数:要申请的内存大小 * 返回值:申请好的内存的首地址 * 这是一种不好的方式 */ int * funcC(int size)

以函数返回值做参数时,函数调用的顺序

环境:vs2013 在下面的代码中 1 //类似于下面的代码 2 3 foo(char*,char*,char*); 4 5 char* str ="A#B#C"; 6 7 foo(strtok(str,"#"),strtok(NULL,"#"),strtok(NULL,"#")); 预计让函数foo得到("A","B","C")的参数,程序编译的时候没问题,但是运行

函数指针与指针函数返回值的区别

指针函数是指带指针的函数,即本质是一个函数.函数返回类型是某一类型的指针定义: 类型标识符 *函数名(参数表)eg: int *f(x,y);函数指针是指向函数的指针变量,即本质是一个指针变量.int (*f) (int x); /* 声明一个函数指针 */ f=func; /* 将func函数的首地址赋给指针f */ 函数指针与指针函数返回值的区别,码迷,mamicode.com

对象做函数参数和函数返回值时,调用复制构造函数,构造函数,析构函数的情况

// 对象做函数参数和返回值.cpp : 定义控制台应用程序的入口点.//exit(0)表示正常退出程序,exit(0)表示异常退出 //在调用input时,编译器用对象A去创建了形参对象temp,调用了复制构造函数,对象A中的数据复制给了对象temp// 在input函数中,执行temp.set(s),为对象temp中数据成员str申请了动态储存空间,并设置了输入的字符串//并没有改变实参A中的数据成员str的储存空间,故在执行语句A.show()后输出的字符串并没有改变.在函数调用结束后 /