宏伟精讲·linux system()函数完全解密

宏伟精讲·linux system()函数完全解密

system()能让我们在自己的程序中调用系统的脚本和已编译好的程序,是一个非常简单、便捷的接口。
但很多程序员都对这个函数又爱又恨,爱是因为用它可以省很多事,恨是因为网上都说它会给程序带来
莫名其妙的BUG。但这个是system()函数的原罪吗?(system():怪我咯?)害怕源于不了解,下面
让我们系统的了解一下system()的用法,和所谓的坑。

一、基本功能和测试

1.头文件包含

#include <stdlib.h>

2.函数原型

/*
*功能:在C程序中执行字符串指定的系统命令或程序
*返回值:
*  1:命令为NULL
* -1:创建子进程失败
*  0x7f00:命令无法执行(子进程返回127)*  
*  其他值:命令的返回值或退出码。
*命令的返回值或退出码格式说明:
*  Bits 15-8 = 进程返回值或退出码。
*  Bit     7 = 是否产生了core dump。
*  Bits  6-0 = 导致进程被杀死的信号值。
*  常用异常码解析宏:
*  WIFEXITED(status)   正常退出返回非零值
*  WEXITSTATUS(status) 取得返回值或退出码
*  WIFSIGNALED(status) 被信号杀死返回非零
*  WTERMSIG(status)    取得杀死它的信号值
*  WIFSTOPPED(status)  被信号暂停返回非零
*  WSTOPSIG(status)    取得暂停它的信号值
int system(const char *__command);

3.函数流程

|-cmd==NULL? --------------YES---->return 1
|-创建子进程--------------失败---->return -1
|-执行cmd-----------------失败---->return 0x7f00(32512)
|-等待cmd执行完毕--等待cmd失败---->return -1
|--------------------------------->return cmd返回值或退出码

4.测试代码

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
*演示system返回值使用,空命令处理和信号处理跟system()不一样。
int mysystem(const char * __command)
        pid_t pid;
        int retval=0;
        if(NULL==__command){
                return 1;
        if((pid=fork())<0){//fork error
                return -1;
        else if(pid==0){
                //use __command to replace current process
                execl("/bin/sh", "sh", "-c", __command, (char *)0);
                return 127;
        else{
                while(waitpid(pid,&retval,0)<0){
                        if(EINTR!=errno){
                                retval = -1;
                                break;
        return retval;
int main(int argc,const char **argv)
        int ret=0;
        ret=mysystem(argv[1]);
        printf("mysystem ret=%d\n",ret);
        ret=system(argv[1]);
        printf("system ret  =%d\n",ret);
        return 1;
}

5.测试结果

(1)cmd为空

(2)未知命令

(3)执行成功

返回1的是第二个./mysys打印,表示cmd为空。

返回256的是第一个./mysys打印,表示“./mysys”执行成功,并返回了1(256=0x100)

二、注意事项

1.阻塞进程

system会阻塞当前进程,但是当前进程的其他线程不会被阻塞。

可对上面的代码稍加改动,然后测试:

#include <pthread.h>
void *threadloop(void *arg)
        while(1){
                printf("this is thread\n");
                usleep(100000);
int main(int argc,const char **argv)
        int ret=0;
        pthread_t tid;
        pthread_create(&tid,NULL,threadloop,NULL);
        ret=mysystem(argv[1]);
        printf("mysystem ret=%d\n",ret);
        ret=system(argv[1]);
        printf("system ret  =%d\n",ret);
        pthread_join(tid,NULL);
        return 1;
}

测试结果:system会阻塞当前进程,但是当前进程的其他线程不会被阻塞。

2.返回值多

system()返回值多而复杂,咋一看五花八门,所以必须妥善处理,下面是一个返回值处理的范本。

int main(int argc,const char **argv)
        int ret=0;
        const char *cmd=argv[1];
        ret=system(cmd);
        printf("system ret  =%d\n",ret);
        if(1==ret){
                printf("程序命令为空\n");
        else if(-1==ret){
                printf("创建命令子进程失败\n");
        else if(0x7f00==ret){
                printf("命令错误,无法执行\n");
        else{
                if(WIFEXITED(ret)){
                        printf("程序正常结束,返回值:%d\n",WEXITSTATUS(ret));
                else if(WIFSIGNALED(ret)){
                        printf("程序被信号杀死,信号值:%d\n",WTERMSIG(ret));