说明
- system是标准库中定义的函数接口,在window和Linux上都得到了实现。
函数介绍
- 功 能: 执行一条脚本命令(windows平台的DOS命令或者linux平台的shell命令)。
- 函数声明
#include <stdlib.h>
int system(const char *command);
- 例子:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
system("ls");
return 0;
}
实现原理
- 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;
}
- man中描述
system() executes a command specified in command by calling /bin/sh -c command, and returns after the command has been completed. During execution of
the command, SIGCHLD will be blocked, and SIGINT and SIGQUIT will be ignored.
- 创建一个进程,在该进程中通过sh -c 来执行传入的命令,并且阻塞直到命令执行完成,在执行过程中,SIGCHLD信号将会被阻塞,SIGINT和SIGQUIT信号将会被忽略。
优缺点
优点
- 使用非常简单方便。
- 能够非常简单的实现执行第三方程序或者命令。
缺点
- 性能低
- 创建和销毁进程都需要消耗系统资源,并且为了保证通用,system需要采用sh -c 的方式执行命令,需要创建一个shell环境,性能不高。
- 测试发现通过system调用md5sum和调用相同md5sum库接口,运行时长有10倍的差距。
- 部分信号被忽略
- SIGINT和SIGQUIT信号将会被忽略,如果程序中涉及到信号处理,进程可能由于信号被忽略,导致运行异常。
使用
不要图方便而使用
- 在嵌入式开发中,由于采用C语言开发,C语言功能不强大,很多功能没有库等原因,在中小公司中时常看到system的滥用,例如:system(“rm”); system(“touch xxx”);等基本功能。
- mkdir,rm, touch这些简单的命令,本质上是一个二进制程序,也是调用的系统接口实现的,
- 我们不应该图使用简单就直接使用system去调用这些命令,会降低性能,可以直接调用系统接口。
获取运行结果
- 如果第三方程序实现较为复杂,没有提供库,必须采用system的形式调用,我们也需要注意获取其运行结果。
- 程序使用exit函数来设置进程的退出值时,虽然exit函数的参数类型为int型,但是父进程中只能取到其值的低8位.所以用exit返回值时,高于255的值是没有意义的。
- system函数,返回值是int类型,由两部分组成的,低8位值表示所执行的脚本在执行过程中所接收到的信号值,其余的位表示的脚本exit退出时所设置的值。
- 可以使用三个宏来获取命令运行结果。
- 判断子进程是否正常退出,是的话,以下宏返回非0
WIFEXITED(int status)
- 如果子进程正常退出,可通过以下宏获得子进程exit()返回的结束值,先要用WIFEXITED判断是否正常结束。
WEXITSTATUS(int status)
- 如果子进程是因为信号而中断结束则以下宏值为真。
WIFSIGNALED(int status)
- 使用例子:
int get_system_return(const char *cmd)
{
int status = system(cmd);
if (WIFEXITED(status))
{
return WEXITSTATUS(status);
}
return -1;
}