6

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

 3 years ago
source link: https://blog.popkx.com/linux%E4%B8%8B%E7%9A%84c%E8%AF%AD%E8%A8%80%E5%BC%80%E5%8F%9119-%E4%BD%BF%E7%94%A8c%E8%AF%AD%E8%A8%80%E6%89%A7%E8%A1%8Cshell%E5%91%BD%E4%BB%A4/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

发表于 2019-01-07 18:01:11   |   已被 访问: 459 次   |   分类于:   Linux笔记   |   暂无评论

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

system 函数

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

016f29fba2eb69c0930163120875ce59.png

它可以执行一条由参数 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 文件:

8a8187ab887c275d83bd1cbfd5575d81.png

分析 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;
}
8aafb5f95cf40bed0fca216830d5be41.png

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

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

使用 system 注意事项

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

阅读更多:   Linux笔记


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK