本文转载自:http://www.cnblogs.com/mickole/p/3187974.html

一,system()理解

功能:system()函数调用“/bin/sh -c command”执行特定的命令,阻塞当前进程直到command命令执行完毕

原型:

int system(const char *command);

返回值:

如果无法启动shell运行命令,system将返回127;出现不能执行system调用的其他错误时返回-1。如果system能够顺利执行,返回那个命令的退出码。

说明:

man帮助:

#include <stdlib.h>

int system(const char *command);

DESCRIPTION 
       system()  executes a command specified in command by calling /bin/sh -c 
       command, and returns after the command has been completed.  During exe- 
       cution  of the command, SIGCHLD will be blocked, and SIGINT and SIGQUIT 
       will be ignored.

RETURN VALUE 
       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 exit(127).

If the value of command is NULL, system() returns non-zero if the shell 
       is available, and zero if not.

system() does not affect the wait status of any other children.

二,system()函数原理

system函数执行时,会调用fork、execve、waitpid等函数。

linux版system函数的源码:

int system(const char * cmdstring)
{
pid_t pid;
int status;
if(cmdstring == NULL){
return (1);
}
if((pid = fork())<0){
status = -1;
}
else if(pid == 0){
execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
_exit(127); //子进程正常执行则不会执行此语句
}
else{
while(waitpid(pid, &status, 0) < 0){
                 if(errno != EINTER){
status = -1;
break;
}
}
}
return status;
}
  • 函数说明 
    system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令,此命>令执行完后随即返回原调用的进程。 
    在调用system()期间SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。 
    返回值 
    =-1:出现错误  
    =0:调用成功但是没有出现子进程  
    >0:成功退出的子进程的id 
    如果system()在调用/bin/sh时失败则返回127,其他失败原因返回-1。若参数string为空指针(NULL),则返回非零值>。如果system()调用成功则最后会返回 
    执行shell命令后的返回值,但是此返回值也有可能为 system()调用/bin/sh失败所返回的127,因此最好能再检查errno 来确认执行成功。 
    附加说明 
    在编写具有SUID/SGID权限的程序时请勿使用system(),system()会继承环境变量,通过环境变量可能会造成系统安全的问题。

system函数对返回值的处理,涉及3个阶段:

阶段1:创建子进程等准备工作。如果失败,返回-1。 
阶段2:调用/bin/sh拉起shell脚本,如果拉起失败或者shell未正常执行结束(参见备注1),原因值被写入到status的低8~15比特位中。system的man中只说明了会写了127这个值,但实测发现还会写126等值。 
阶段3:如果shell脚本正常执行结束,将shell返回值填到status的低8~15比特位中。 
备注1: 
只要能够调用到/bin/sh,并且执行shell过程中没有被其他信号异常中断,都算正常结束。 
比如:不管shell脚本中返回什么原因值,是0还是非0,都算正常执行结束。即使shell脚本不存在或没有执行权限,也都算正常执行结束。 
如果shell脚本执行过程中被强制kill掉等情况则算异常结束。

如何判断阶段2中,shell脚本子进程是否正常执行结束呢?系统提供了宏:WIFEXITED(status)。如果WIFEXITED(status)为真,则说明正常结束。 
如何取得阶段3中的shell返回值?你可以直接通过右移8bit来实现,但安全的做法是使用系统提供的宏:WEXITSTATUS(status)。

由于我们一般在shell脚本中会通过返回值判断本脚本是否正常执行,如果成功返回0,失败返回正数。 
所以综上,判断一个system函数调用shell脚本是否正常结束的方法应该是如下3个条件同时成立: 
(1)-1 != status 
(2)WIFEXITED(status)为真 
(3)0 == WEXITSTATUS(status) 
注意: 
根据以上分析,当shell脚本不存在、没有执行权限等场景下时,以上前2个条件仍会成立,此时WEXITSTATUS(status)为127,126等数值。 
所以,我们在shell脚本中不能将127,126等数值定义为返回值,否则无法区分中是shell的返回值,还是调用shell脚本异常的原因值。shell脚本中的返回值最好多1开始递增。

示例程序:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h> #define EXIT_ERR(m) \
do\
{\
perror(m);\
exit(EXIT_FAILURE);\
}\
while (0);\ int main(void)
{
int status ;
status = system("ls -l|wc -l"); if(status == -1){
EXIT_ERR("system error");
} else{
if(WIFEXITED(status))
{
if(WEXITSTATUS(status) == 0)
printf("run command successful\n");
else
printf("run command fail and exit code is %d\n",WEXITSTATUS(status));
}
else
printf("exit status = %d\n",WEXITSTATUS(status));
}
return 0;
}

结果:

linux系统编程之进程(七):system()函数使用【转】的更多相关文章

  1. linux系统编程之进程(七):system()函数使用

    一,system()理解 功能:system()函数调用"/bin/sh -c command"执行特定的命令,阻塞当前进程直到command命令执行完毕 原型: int syst ...

  2. linux系统编程之进程(一)

    今天起,开始学习linux系统编程中的另一个新的知识点----进程,在学习进程之前,有很多关于进程的概念需要了解,但是,概念是很枯燥的,也是让人很容易迷糊的,所以,先抛开这些抽象的概念,以实际编码来熟 ...

  3. linux系统编程之信号(七)

    今天继续学习信号,主要是学习关于时间和定时器相关的函数的使用,关于这个实际上有很多内容,这里先简要进行说明,等之后再慢慢进行相关深入,也主要是为接下来要做的一个综合linux系统编程的例子做准备,好了 ...

  4. linux系统编程之进程(六):父进程查询子进程的退出,wait,waitpid

    本节目标: 僵进程 SIGCHLD wait waitpid 一,僵尸进程 当一个子进程先于父进程结束运行时,它与其父进程之间的关联还会保持到父进程也正常地结束运行,或者父进程调用了wait才告终止. ...

  5. linux系统编程之进程(八):守护进程详解及创建,daemon()使用

    一,守护进程概述 Linux Daemon(守护进程)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.它不需要用户输入就能运行而且提供某种服务,不是对整个 ...

  6. Linux系统编程——Daemon进程

    目录 Daemon进程介绍 前提知识 Daemon进程的编程规则 Daemon进程介绍 Daemon运行在后台也称作"后台服务进程". 它是没有控制终端与之相连的进程.它独立与控制 ...

  7. Linux系统编程:进程控制

    一.进程相关操作与编程对应函数 1.进程创建:两种方式来实现. ①fork:创建一个子进程,父子进程共享一份代码程序,但是各有一份独立的数据,为了效率和保持数据的独立采用写时复制技术(COW).运行无 ...

  8. linux系统编程之进程(五)

    今天继续学习系统编程,学习的主题还是进程,今天主要讨论的是守护进程相关的概念,开始进入正题: 什么是守护进程:       守护进程的创建步骤: 在描述它之前,首先得先了解两个概念:进程组.会话期: ...

  9. linux系统编程之进程(二):进程生命周期与PCB(进程控制块)

    本节目标: 进程状态变迁 进程控制块 进程创建 进程撤消 终止进程的五种方法 一,进程状态变迁 进程的三种基本状态 就绪(Ready)状态 当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便 ...

随机推荐

  1. str内部方法释义

    1. __add__:字符串拼接 [示例]:>>> str1=‘good’>>> str1.__add__(‘morning’)>>> ‘good ...

  2. Java学习之接口概念

    Java语言只支持单重继承,不支持多继承,即一个类只能有一个父类.但是在实际应用中,又经常需要使用多继承来解决问题.为了解决该问题,Java语言提供接口来实现类的多继承问题. 接口(英文interfa ...

  3. RobotFramework:切换页面和Frame框架

    切换页面主要有以下两种情况 在浏览器上打开多个窗口(Windows),在窗口内切换 打开多个浏览器(Browser),在多个浏览器内切换 1. 切换窗口 该操作适用于:打开两(多)个窗口页面,在打开的 ...

  4. 七牛云赵之健:多维度融合赋能视频 AI 的实践

    6 月 30 日下午,赵之健在七牛架构师实践日第二十九期进行了<多维度融合赋能视频 AI 的实践>为题的实战分享. 
 作者简介: 
  赵之健,七牛人工智能实验室资深算法工程师, 七 ...

  5. HDU 5242 利用树链剖分思想进行贪心

    题目大意: 在给定带权值节点的树上从1开始不回头走到某个底端点后得到所有经过的点的权值后,这些点权值修改为0,到达底部后重新回到1,继续走,问走k次,最多能得到多少权值之和 这其实就是相当于每一次都走 ...

  6. react.js 高阶组件----很简单的实例理解高阶组件思想

    调试代码之前,我设置了两个缓存 分别是username和content 在控制台console设置两个缓存代码 localStorage.setItem('username','老王')localSt ...

  7. POJ 3615 Cow Hurdles

    http://poj.org/problem?id=3615 floyd 最短路径的变形 dist[i][j]变化为 : i j之间的最大边 那么输入的时候可以直接把dist[i][j] 当作i j ...

  8. Python基础教程笔记——第4章:字典

    字典 字典是Python唯一内建的数学映射类型,字典中的值没有特殊的顺序,键可以是数字,字符串,甚至是元组 字典的创建: 字典由键值对构成,字典中键是唯一的,而值不唯一.>>> a_ ...

  9. 2014 蓝桥杯 预赛 c/c++ 本科B组 第九题:地宫取宝(12') [ dp ]

      历届试题 地宫取宝   时间限制:1.0s   内存限制:256.0MB     锦囊1   锦囊2   锦囊3   问题描述 X 国王有一个地宫宝库.是 n x m 个格子的矩阵.每个格子放一件 ...

  10. 洛谷——P1262 间谍网络

    P1262 间谍网络 题目描述 由于外国间谍的大量渗入,国家安全正处于高度的危机之中.如果A间谍手中掌握着关于B间谍的犯罪证据,则称A可以揭发B.有些间谍收受贿赂,只要给他们一定数量的美元,他们就愿意 ...