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

如题所述

题主可以使用 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 这句话就会被输出到屏幕上。

温馨提示:答案为网友推荐,仅供参考
第1个回答  推荐于2018-03-28
可以通过system函数,调用shell命令。
1 函数原型:
int system(const char *cmd);
2 功能:
调用cmd内容的系统命令,即shell命令。
3 头文件:
stdlib.h
4 举例:
system("ls");
打印当前工作目录下的文件。
第2个回答  2015-10-29
1、可以使用system函数调用。system("shell_command");可以实现在shell中调用shell_command的作用。
2、例如设置网卡IP为192.168.1.100,可以写作
system("ifconfig eth0 192.168.1.100");
第3个回答  2015-07-23
system 这个函数可以帮到你。 参数就一个 就是shell命令
第4个回答  2015-07-23
参数type可使用“r”代表读取,“w”代表写入。依照此type值,popen()会建立管道连到子进程的标准输出设备或标准输入设备,然后返回一个文件指针。随后进程便可利用此文件指针来读取子进程的输出设备或是写入到子进程的标准输入设备中。此外,所有使...

相关了解……

你可能感兴趣的内容

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 非常风气网