• 好好学习,天天向上~
  • 欢迎欢迎~

linux下的C语言开发19,使用C语言执行shell命令

linux笔记 lcc 323℃ 0评论

上一节使用基于 linux 中的信号机制,使用 C语言实现了类似于 python 的 try 语句,使得我们的 C语言程序也能够处理 8/0 这种 0 做除数的无意义问题,也能用其来捕捉令人头疼的段错误等崩溃性错误。

system 函数

本节再回到 linux,来看看另一个比较有意思的C语言函数——system函数。system 的函数原型如下:

它可以执行一条由参数 command 指定的 shell 命令,调用 system(command) 函数和在 shell 中执行下面的命令是相似的:

# /bin/sh -c command

现在来写一个 C语言程序测试一下 system 函数:

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

int main()
{
    system("touch test_system");
    return 0;
}

按照分析,以上代码应该就相当于在 shell 中执行了

# touch test_system

也即在当前目录创建了 test_system 文件。编译并执行,发现与预期一致,C语言程序的确在当前目录下创建了 test_system 文件:

分析 system 函数,并使用 C 语言实现它

以上C语言代码并没有关心 system 函数的返回值,这在实际开发中是不严谨的。那么,system 函数的返回值是什么呢?继续查看手册,会发现 system 函数应该是由 fork,wait,exec 函数族实现的,它的返回值就与这三个函数相关。

所以如果 fork 失败,system 函数会返回 -1。如果 wait 失败,则会返回 WEXITSTATUS(status),status 是 shell 命令的返回状态码。如果传给 system 的 shell 命令执行失败,则就相当于 shell 执行了 exit(127)。

fork,wait,exec 函数族我们之前都介绍过。现在仔细思考一下,system 函数的实现应该不难,无非就是 fork 出一个子进程调用 exec 函数族执行 shell 命令,然后在父进程里 wait 子进程返回。现在使用 C语言代码实现之,请看:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int mysystem(char* cmd)
{
    pid_t pid;
    int ret;
    if(NULL==cmd)
        return 1;
    pid = fork();
    switch(pid){
        case -1:
            ret = -1;
            break;
        case 0:
            execl("/bin/sh", "sh", "-c", cmd, NULL);
            exit(127);
        default:
            while(waitpid(pid, &ret, 0)<0);
            break;
    }
    return ret;
}

int main()
{
    mysystem("touch test_system_by_my_system");
    return 0;
}


代码还是非常简单的,唯一值得说明的是 case 0,execl 函数如果执行成功,就会替换当前进程,exit 函数也就没机会执行。exit 只有在 execl 函数执行失败时才有可能执行。现在编译执行,发现的确成功了:

需要说明的是,这里实现的 mysystem 还没有考虑信号处理。

使用 system 注意事项

根据 man 手册,system 不应用于设置用户 ID 或者组 ID,这么做可能会有奇怪的现象发生(恶意用户可能会修改 system 的执行环境)。如果希望修改用户 ID 或者组 ID,则应使用 exec 函数族代替(不能是 execlp 和 execvp 函数)。实际上,v2 版本的 bash 已经弃用 system 修改设置用户 ID 或者组 ID 的功能了。


linux下的C语言开发19,使用C语言执行shell命令 - 刘冲的博客(https://blog.popkx.com) 原创版权所有,转载请注明出处。
点赞 (0)分享 (0)
发表我的评论
取消评论
表情     6 + 3 = ? (必填)