Linux C编程中,调用另一个可执行文件或调用命令可以使用system函数和exec系列的函数。

下面关于system函数的一些方法和使用做一个简单的记录。

system在程序中执行一个命令字符串很方便,在man system的时候,可以看到

#include <stdlib.h>
int system(const char *command);

system()通过调用/bin/sh -c命令执行命令中指定的命令,并在命令完成后返回。在执行命令期间,SIGCHLD将被阻塞,SIGINTSIGQUIT将被忽略。
阻塞:就是忙完再说
忽略:收到了但是没有任何动作

比如在当前路径下,存在一个名为 a.out 的可执行文件,那么在一个进程main中使用system来执行这个a.out的程序,则可以直接使用

sysRet = system("./a.out");

system是在其实现中调用了fork + exec + waitpid, 执行完毕之后,回到原先的程序中去。继续执行下面的部分。

至于system的返回值
1、如果command是一个空指针,则仅当命令处理程序可用时,system返回非0值。可是使用这一个特性测试当前系统是否支持system函数,UNIX中总是可用的。
2、如果fork失败或者waitpid返回除EINTR之外的出错,返回-1,且设置errno。
3、如果exec失败(即不能执行shell),返回值如同shell实行了exit(127)一样。
4、如果fork,exec,waitpid都执行成功,那返回值是shell的终止状态,可以参见waitpid的说明使用system而不直接使用fork和exec的优点是:system进行了所需的各种出错的处理以及各种信号的处理
可以看到system的实现代码为:

#include <sys/wait.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>

int system(const char *cmdstring)
{
    pid_t pid;
    int status;
    struct sigaction ignore,saveintr,savequit;
    sigset_t chldmask, savemask;
 
    if(cmdstring == NULL)
        return(1); /* always a command processor with UNIX */
 
    ignore.sa_handler = SIG_IGN; /* ignore SIGINT and SIGQUIT */
    sigemptyset(&ignore.sa_mask);
    ignore.sa_flags = 0;
    if(sigaction(SIGINT,&ignore,&saveintr) < 0)
        return(-1);
 
    if(sigaction(SIGQUIT,&ignore,&savequit) < 0)
        return(-1);
 
    sigemptyset(&chldmask);   /*now block SIGCHLD*/
    sigaddset(&chldmask,SIGCHLD);
    if(sigprocmask(SIG_BLOCK,&chldmask,&savemask) < 0)
        return(-1);
    if((pid = fork()) < 0)
        status = -1;  /* probably out of processes*/
    else if(pid == 0 ){  /* child */
        /* restore previous signal  action & reset signal mask*/
        sigaction(SIGINT,&saveintr,NULL);
        sigaction(SIGQUIT,&savequit,NULL);
        sigprocmask(SIG_SETMASK,&savemask,NULL);
        execl("/bin/sh","sh","-c",cmdstring,(char *)0);
        _exit(127);  /*exec error */
    }else{  /*parent*/
        while(waitpid(pid,&status,0) < 0){
            if(errno != EINTR){
                status = -1;  /* error other than EINTR from waitpid() */
                break;
            }
        }
    }
    /*restore previous signal actions & reset signal mask*/
    if(sigaction(SIGINT,&saveintr,NULL) < 0)
        return(-1);
    if(sigaction(SIGQUIT,&savequit,NULL) < 0)
        return(-1);
    if(sigprocmask(SIG_SETMASK,&savemask,NULL) < 0)
        return(-1);
 
    return(status);
}


几个system的简单使用:

1、调用系统命令,打印出当前目录下的所有文件和文件夹。

#include <stdio.h>
#include <stdlib.h>

int main(int argc, const char *argv[])
{
    int ret = 1;
    if(argc >= 2) printf("argv[1] = %s\r\n", argv[1]);
    else printf("argv[0] = %s\r\n", argv[0]);
    ret = system("ls -a");
    printf("ret = %d, Byebye...\r\n");
    return 0;
}

上面的代码文件名称为system1.c,编译生成可执行文件为system1
运行时候没有传入命令行参数,可以看到运行结果,列出了当前目录下的所有的文件(夹)

2、由一个程序调用另外一个程序(以调用上面的一个程序为例,不传入命令行参数)

#include <stdio.h>
#include <stdlib.h>

int main(int argc, const char *argv[])
{
    int ret = 1;

    ret = system("./system1");

    printf("ret = %d\r\n", ret);

    return 0;
}

上面的代码文件名称为system2.c,编译生成可执行文件为system2
直接运行system2,可以看到运行结果,成功的调用了程序system1,列出了当前目录下的所有的文件(夹),并且成功返回0


3、由一个程序调用另外一个程序(以调用上面的一个程序为例,传入命令行参数)

#include <stdio.h>
#include <stdlib.h>

int main(int argc, const char *argv[])
{
    int ret = 1;

    ret = system("./system1 args");

    printf("ret = %d\r\n", ret);

    return 0;
}

重新生成可执行文件system2,可以看到运行结果,成功的调用了程序system1,列出了当前目录下的所有的文件(夹),成功的传递命令行参数args,并且成功返回0

4、那么对于另外一种情况,如果两个程序是无限循环执行的

那么在采用的system调用另外一个无线循环的程序的时候,可以看到,调用者和被调用者都是运行的状态中,可以参见
点我就是哦

Logo

更多推荐