-
Linux下正确运用system函数以及理清返回值问题
2020-05-12 23:24:22在linux下想调用shell脚本,肯定对于使用system不陌生?但是使用system()函数一定要谨慎。...这么说还是比较通俗易懂的,下面详细描述system: #include <stdlib.h> int system(const char *在linux下想调用shell脚本,肯定对于使用system不陌生?但是使用system()函数一定要谨慎。必要要理清返回值问题以及调用机制。不然很容易造成程序的异常和bug等问题。
system函数介绍
system的作用是在shell终端执行command。简单的说就是在C中执行system(“pwd”)这行代码的含义就相当于在shell执行pwd一样。这么说还是比较通俗易懂的,下面详细描述system:
#include <stdlib.h> int system(const char *command);
我们开看看
man 3 system
system() executes a command specified in command by calling /bin/sh -c command, and returns after the command has been com‐
pleted. During execution of the command, SIGCHLD will be blocked, and SIGINT and SIGQUIT will be ignored.大体的意思就是:
system()函数调用/bin/sh来执行参数指定的命令,/bin/sh 一般是一个软连接,指向某个具体的shell,比如bash,-c选项是告诉shell从字符串command中读取命令;
system()函数返回值还是通过
man 3 system
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 nonzero if the shell is available, and zero if not.
system() does not affect the wait status of any other children.大体的意思就是:
为了更好的理解system()函数返回值,需要了解其执行过程,实际上system()函数执行了三步操作:
1.fork一个子进程(创建子进程等准备工作);
2.在子进程中调用exec函数去执行command(调用/bin/sh拉起shell脚本);
3.在父进程中调用wait去等待子进程结束。从上面man手册可知,不管shell脚本返回什么值,只要调用了
/bin/sh
,并且执行过程没有被信号中断,都算正常结束。因为脚本是在子进程中执行的,所以要想获取脚本是否执行成功的方法只能用系统提供的两个宏。WIFEXITED用来判断阶段二的返回值
WEXITSTATUS用来判断阶段三的返回值下面的例子是判断一个脚本是否执行成功。
test1.sh
#! /bin/bash #basic for command for test in A B C D E F do echo "The next state is $test" done
main.c
#include <stdio.h> #include <stdlib.h> #include <sys/wait.h> #include <sys/types.h> int main(int argc, char **argv) { pid_t status; status = system("./test1.sh"); if (-1 == status) { printf("system error!"); } else { printf("exit status value = [0x%x]\n", status); if (WIFEXITED(status)) //正确退出 { if (0 == WEXITSTATUS(status)) //操作成功 { printf("run shell script successfully.\n"); } else //操作失败 { printf("run shell script fail, script exit code: %d\n", WEXITSTATUS(status)); } } else //错误退出,这里属于信号中断了,WEXITSTATUS一定是0了 { printf("exit status = [%d]\n", WEXITSTATUS(status)); } } return 0; }
编译输出:
判断一个脚本是否执行成功,应该满足三个条件:
-1 != ret
WIFEXITED(ret)为真
0 == WEXITSTATUS(ret)当shell脚本不存在时:
当shell脚本不存在时、没有执行条件等,前两个条件也会成立,此时WEXITSTATUS(ret)为127,所以shell脚本中不能将127作为返回值,shell脚本中的异常返回值最好从1开始递增,成功返回0。
system函数源码
好了,再先看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接受的命令为NULL时直接返回,否则fork出一个子进程,因为fork在两个进程:父进程和子进程中都返回。
这里要检查返回的 pid,fork在子进程中返回0,在父进程中返回子进程的pid,父进程使用waitpid等待子进程结束,子进程则是调用execl来启动一个程序代替自己,execl("/bin/sh", “sh”, “-c”, cmdstring,(char*)0)是调用shell,这个shell的路径是/bin/sh,后面的字符串都是参数,然后子进程就变成了一个 shell进程,这个shell的参数是cmdstring,就是system接受的参数。
哎呀,终于说完了!!
总结
system用起来看似简单,但是有很多隐藏的坑需要自己深入理解原理才能更好地使用。也可以用其他实现方式完成相同的功能。
还有,在编写使用system函数的程序时,一定要正确地解析返回值。如果无法启动shell运行命令,system将返回127;出现不能执行system调用的其他错误时返回-1。如果system能够顺利执行,返回那个命令的退出码。
欢迎关注公众号【程序猿编码】,添加本人微信号(17865354792),回复:领取学习资料。或者回复:进入技术交流群。网盘资料有如下: -
PHP基础教程 是一个比较有价值的PHP新手教程!
2010-04-24 18:52:44我将在下面大概介绍。 if, else, elseif, if(): endif if (表达式一) { . . . } elseif (表达式二) { . . . } else { . . . } // 或者像Python一样 if (表达式一) : . . . . . . elseif (表达式二) : . . . else :... -
linux 下socket通信中select的用法实例
2013-03-14 18:37:46可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如connect、accept、recv或recvfrom这样的阻塞程序(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件的发生,... -
Qt Creator 的安装和hello world 程序+其他程序的编写--不是一般的好
2011-01-28 17:02:082.运行Qt Creator,首先弹出的是欢迎界面,这里可以打开其自带的各种演示 程序。 3.我们用File->New 菜单来新建工程。 4.这里我们选择Qt4 Gui Application。 5.下面输入工程名和要保存到的文件夹路径。我们这里的... -
你必须知道的495个C语言问题
2015-10-16 14:14:28不同编译器给出不同的i值,有的为3,有的为4,哪个是正确的? *3.4 有这样一个巧妙的表达式:a^=b^=a^=b;它不需要临时变量就可以交换a和b的值。 3.5 可否用显式括号来强制执行我所需要的计算顺序并控制相关的副... -
《你必须知道的495个C语言问题》
2010-03-20 16:41:18不同编译器给出不同的i值,有的为3,有的为4,哪个是正确的? 34 *3.4 有这样一个巧妙的表达式:a^= b^= a^= b; 它不需要临时变量就可以交换a和b的值。 34 3.5 可否用显式括号来强制执行我所需要的计算顺序并... -
关于代码的一些问题
2020-12-01 16:57:35UP感兴趣的话也可以去查一查main()函数返回值到底意味着什么。 </li></ol> 代码的问题其实很多,限于篇幅先只写这么多。说实话,并不是想打击UP学习编程的积极性。而是我相信一些建议能够帮助UP写出更好... -
你必须知道的495个C语言问题(高清版)
2010-03-31 16:24:09不同编译器给出不同的i值,有的为3,有的为4,哪个是正确的? 34 *3.4 有这样一个巧妙的表达式:a^= b^= a^= b; 它不需要临时变量就可以交换a和b的值。 34 3.5 可否用显式括号来强制执行我所需要的计算顺序并... -
C语言程序设计标准教程
2009-05-22 18:41:51此类函数被调用执行完后将向调用者返回一个执行结果, 称为函数返回值。如数学函数即属于此类函数。 由用户定义的这种要返回函数值的函数,必须在函数定义和函数说明中明确返回值的类型。 (2)无返回值函数 此类... -
LINGO软件的学习
2009-08-08 22:36:50LINGO内置的建模语言是一种描述性语言,用它可以描述现实世界中的一些问题,然后再借助于LINGO求解器求解。因此,集属性的值一旦在模型中被确定,就不可能再更改。在LINGO中,只有在初始部分中给出的集属性值在以后... -
VC++科学计算器的设计V1_4Beta.rar
2010-03-23 04:54:59显然,我们真正需要的是能够完成动态表达式解释执行的函数库调用。以上软件没有我们需要的功能。(注:利用MATLAB的计算引擎技术与DDE数据交换技术也可以间接实现表达式动态解释执行的目的,但是其执行效率很低,并且... -
超级有影响力霸气的Java面试题大全文档
2012-07-18 09:47:04如果该值为false,说明程序已经处于不正确的状态下,系统将给出警告或退出。一般来说,assertion用于保证程序最基本、关键的正确性。assertion检查通常在开发和测试时开启。为了提高性能,在软件发布后,assertion... -
最权威的C++教程_C++_Primer_Plus中文第五版+C++_Primer中文第四版(都含源码+习题)(共4分卷)分卷1
2010-06-23 17:33:55对象声明描述的是存 储在对象中的信息以及可对对象执行的操作(类方法)。对象的某些组成部分对于外界来说是可见的(公有部 分),而某些部分却是隐藏的(私有部分)。特殊的类方法(构造函数和析构函数)在对象创建和释放... -
最权威的C++教程_C++_Primer_Plus中文第五版+C++_Primer中文第四版(都含源码+习题)(共4分卷)分卷2
2010-06-23 17:47:19对象声明描述的是存 储在对象中的信息以及可对对象执行的操作(类方法)。对象的某些组成部分对于外界来说是可见的(公有部 分),而某些部分却是隐藏的(私有部分)。特殊的类方法(构造函数和析构函数)在对象创建和释放... -
最权威的C++教程_C++_Primer_Plus中文第五版+C++_Primer中文第四版(都含源码+习题)(共4分卷)分卷3
2010-06-23 18:03:39对象声明描述的是存 储在对象中的信息以及可对对象执行的操作(类方法)。对象的某些组成部分对于外界来说是可见的(公有部 分),而某些部分却是隐藏的(私有部分)。特殊的类方法(构造函数和析构函数)在对象创建和释放... -
php高级开发教程说明
2008-11-27 11:39:22点,这些方案一般分为两类:简短的变量和函数名及谈话式的变量和函数名(描述变量类型和 目的的更长的名字)。 某个电话目录可能是这个样子的,如表1 - 1所示。 第1章认开发思想部分3 下载 表1-1 电话目录 姓名地址... -
你必须知道的495个C语言问题(PDF)
2009-09-15 10:25:473, 有的为4, 哪个是正确的? . . . . . . . . . . . . . . . . . . . . . 14 3.4 这是个巧妙的表达式: a ˆ= b ˆ= a ˆ= b 它不需要临时变量就可 以交换a 和b 的值。. . . . . . . . . . . . . . . . . . . . . . .... -
初学字符串的实际工程问题4,5,6
2018-11-24 11:49:02对于没有给定数据长度的情况,可以利用gets( )函数的返回值为为空(它输入数据已经输入完毕)来判断输入是否结束。例如,如下形式。 char str[足够大的元素个数]; while (gets(str)!=NULL) { //每循环一次,处理... -
jQuery详细教程
2013-04-25 14:16:42语法 描述 $(this) 当前 HTML 元素 $("p") 所有 <p> 元素 $("p.intro") 所有 class="intro" 的 <p> 元素 $(".intro") 所有 class="intro" 的元素 $("#intro") id="intro" 的第一个元素 $("ul li:first") 每个 <ul> ... -
java经典面试2010集锦100题(不看你后悔)
2011-02-21 12:43:25有关类Demo,描述正确的是:(选择1项) A) 当创建一个Demo类的实例对象时,count的值为0。 B) 当创建一个Demo类的实例对象时,count的值是不确定的。 C) 超类对象中可以包含改变count 值的方法。 D) Demo的子类对象... -
华为编程开发规范与案例
2008-09-04 16:44:5611群是四个群中最小的群,其中继计次表位于缓冲区的首位,打完电话后查询内存发现出中继群号在内存中是正确的,取完话单后再查就不正确了。 结 论: 话单池的一个备份指针Pool_head_1和中继计次表的头指针重合,... -
C语言FAQ 常见问题列表
2010-10-28 16:41:29不同编译器给出不同的结果, 有的为 3, 有的为 4, 哪个是正确的? o 4.4 这是个巧妙的表达式: a ^= b ^= a ^= b 它不需要临时变量就可以交换 a 和 b 的值。 o 4.5 我可否用括号来强制执行我所需要的计算顺序? o ... -
java面试宝典
2013-02-28 16:04:01Overloaded 的方法是否可以改变返回值的类型? 10 27、描述一下JVM 加载class 文件的原理机制? 10 28、char 型变量中能不能存贮一个中文汉字?为什么? 10 29、abstract class 和interface 有什么区别? 10 30、Static ... -
C#微软培训教材(高清PDF)
2009-07-30 08:51:1710.3 构造函数和析构函数 .119 10.4 小 结 .122 第十一章 方 法 .124 11.1 方法的声明.124 11.2 方法中的参数.125 11.3 静态和非静态的方法.129 11.4 方法的重载.130 11.5 操作符重载.134 11.6 小 ... -
千方百计笔试题大全
2011-11-30 21:58:33Overloaded 的方法是否可以改变返回值的类型? 10 27、描述一下JVM 加载class 文件的原理机制? 10 28、char 型变量中能不能存贮一个中文汉字?为什么? 10 29、abstract class 和interface 有什么区别? 10 30、Static ... -
Oracle SQL高级编程(资深Oracle专家力作,OakTable团队推荐)--详细书签版
2013-02-04 12:43:52他认为对于SQL的学习是永无止境的,相信每一个查询Oracle数据库的人都需要精通SQL语言,才能写出高效的查询。他参与本书的编写就是为了帮助别人实现这一目标。 目录 封面 -11 封底 -10 扉页 -9 版权 -8 版权声明 -7... -
windows 程序设计
2011-07-24 21:16:30每个函数都有一个描述名称,例如CreateWindow。该函数(如您所猜想的)为程序建立新窗口。所有应用程序可以使用的Windows函数都在表头文件里预先声明过。 在Windows程序中,使用Windows函数的方式通常与使用如...
-
GNU:GCC -O 优化等级
-
JavatestWebservice.rar
-
你好,对话框
-
使用HTTP网络技术构建灵活的RationalClearCase系统
-
【Python-随到随学】 FLask第一周
-
紧凑的双频段单端至平衡功率分配器,带有开放/短端抽头
-
ABAP校验时间日期格式
-
追踪Android-源码
-
【爱码农】C#制作MDI文本编辑器
-
MySQL 主从复制 Replication 详解(Linux 和 W
-
hadoop分析
-
turlacz:Discord机器人:骰子滚轮和主动追踪器-源码
-
【布道者】Linux极速入门
-
pageHelper分页
-
Spring Cloud微服务学习系列1 系统架构的演变
-
python地理空间:地理空间发现项目的集合-源码
-
使用MEMS技术的波导和表面安装封装的小型W波段间隙波导带通滤波器
-
MMM 集群部署实现 MySQL 高可用和读写分离
-
QT 获取QTextEidt 自动换行后的行数
-
如何使用mybatis(笔记)