如何在C语言中执行shell命令

 我来答
第一碗羊杂割
推荐于2016-08-29 · TA获得超过6145个赞
知道大有可为答主
回答量:1107
采纳率:80%
帮助的人:563万
展开全部

题主可以使用 exec 系列函数。这系列函数定义在 unistd.h 头文件中,所以使用前请包含这个头文件。这系列函数共有五个,

execl, execlp, execv, execvp, execle

其中常用的是前四个。前四个函数的原型为:

int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);

这四个函数的主要差别就在于参数的类型和用不用输入命令的绝对路径上。

以路径形式来分,凡是函数名中带 p 的(execlp,execvp)都只需要提供命令的名,函数会自动在当前的环境变量 $PATH 中查找命令的路径。而不带 p 的(execl,execv)必须要提供命令的绝对路径,否则函数会找不到这个命令的位置。这里以 execl 和 execlp 为例,以下运行

ls -l

命令的代码:


#include <stdio.h>
#include <unistd.h>

int main() {

    // exec 系列函数出错时会返回 -1,平常返回 0,所以可以
    // 据此来打印错误信息
    // 第一个 ls 是命令的名称,execlp 函数会自动在 $PATH
    // 中寻找这个命令。
    // 后面一个 ls 是要在 shell 中输入的第一个参数
    //(也就是命令名称本身)
    // 使用 NULL 作为参数结尾标记是 exec 系列函数的要求。
    if (execlp("ls", "ls", "-l", NULL) == -1)
        perror("Error Executing Command.\n");
    return 0;
    
}

在 shell 中运行这个 C 程序会输出



和你直接在 shell 中写 ls -l 的效果是一样的。然而,如果你使用不带 p 的 execl, 那么这样写就会报错。


#include <stdio.h>
#include <unistd.h>

int main() {

    // execl 只接受命令的绝对路径,所以必须输入完整的
    // 路径 /bin/ls,即
    // if (execl("/bin/ls", "ls", "-l", NULL) == -1)
    if (execl("ls", "ls", "-l", NULL) == -1)
        perror("Error Executing Command.\n");
    return 0;
    
}

输出结果为:



以参数类型来分,凡是函数名中带 l 的(execl,execlp)都需要把系统命令的参数全部传递给函数,而凡是函数名中带 v 的(execv,execvp)都需要把系统命令的参数统一放在一个数组里,然后把这个数组传递给函数。


比如刚才这个


#include <stdio.h>
#include <unistd.h>

int main() {

    if (execlp("ls", "ls", "-l", NULL) == -1)
        perror("Error Executing Command.\n");
    return 0;
    
}


如果改用 execvp 来写的话就是


#include <stdio.h>
#include <unistd.h>

int main() {

    // 这个字符串数组存有所有参数(包括命令名本身和
    // 最后的 NULL)
    char * argv[] = {"ls", "-l", NULL};
    
    // 这里只需将命令名称和参数数组传递给 execvp 函数即可,
    // 无需将参数一个个传递。同样函数会自动在 $PATH 
    // 中查找命令
    if (execvp("ls", argv) == -1)
        perror("Error Executing Command.\n");
    return 0;
    
}


运行结果同样和直接写 ls -l 的效果相同。

execv 和 execvp 的区别也在于是否必须输入绝对路径,就不赘述了。


要注意的一点是,如果执行成功,exec 系列函数开启的新进程会完全代替当前的进程,也就是说当前进程会消失。所以一般会将 exec 和 fork 连用,先 fork 出一个子进程,然后在这个子进程中使用 exec 运行别的程序,防止父进程被 exec 覆盖。比如刚才的代码稍微改一下


#include <stdio.h>
#include <unistd.h>

int main() {

    char * argv[] = {"ls", "-l", NULL};
    if (execvp("ls", argv) == -1)
        perror("Error Executing Command.\n");
        
    // 加入一个 printf 语句
    printf("Main process is still running.\n");
    return 0;
    
}


运行后并不会出现 Main process is still running 这句话,因为 exec 后 main 函数执行产生的进程已经被 ls 命令产生的进程完全覆盖了,所以 exec 函数以下的语句是完全不会执行的。这时就可以使用 fork 来新建一个子进程,在子进程中执行 exec 函数。


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

int main() {
    
    int r;
    
    // fork() 大于零,父进程
    if ((r = fork()) > 0) {
        int status;
        if (wait(&status) != -1) {
            
            // 等待子进程退出
            if(WIFEXITED(status)) {
                printf("Main process is still running.\n");
                return 0;
            }
        }
    
    // fork () 等于零,子进程。子进程中运行 exec    
    } else if (r == 0) {
    
        char * argv[] = {"ls", "-l", NULL};
        if (execvp("ls", argv) == -1)
            perror("Error Executing Command.\n");
        return 0;
    
    // fork() 小于零,出错
    } else {
        perror("Fork");
    }
    
    return 0;
    
}

这样运行结果就变成了



Main process is still running 这句话就会被输出到屏幕上。

风若远去何人留
推荐于2018-03-28 · 知道合伙人互联网行家
风若远去何人留
知道合伙人互联网行家
采纳数:20412 获赞数:450131
专业C/C++软件开发

向TA提问 私信TA
展开全部
可以通过system函数,调用shell命令。
1 函数原型:
int system(const char *cmd);
2 功能:
调用cmd内容的系统命令,即shell命令。
3 头文件:
stdlib.h
4 举例:
system("ls");
打印当前工作目录下的文件。
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
tattackor
2015-10-29 · TA获得超过3.5万个赞
知道大有可为答主
回答量:5083
采纳率:94%
帮助的人:889万
展开全部
1、可以使用system函数调用。system("shell_command");可以实现在shell中调用shell_command的作用。
2、例如设置网卡IP为192.168.1.100,可以写作
system("ifconfig eth0 192.168.1.100");
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
我透明_的
2015-07-23 · TA获得超过190个赞
知道小有建树答主
回答量:214
采纳率:0%
帮助的人:165万
展开全部
system 这个函数可以帮到你。 参数就一个 就是shell命令
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
浅笑Ze安然
2015-07-23 · TA获得超过2036个赞
知道小有建树答主
回答量:1043
采纳率:0%
帮助的人:958万
展开全部
参数type可使用“r”代表读取,“w”代表写入。依照此type值,popen()会建立管道连到子进程的标准输出设备或标准输入设备,然后返回一个文件指针。随后进程便可利用此文件指针来读取子进程的输出设备或是写入到子进程的标准输入设备中。此外,所有使...
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
收起 更多回答(3)
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式