linux的exec和system函数介绍及选择

在应用程序中有时候需要调用第三方的应用,这是常见的需求。此时可以使用linux下的exec命令或system命令达到目的。但是这两个该选择哪个呢?有什么区别?下面总结介绍下。

exec和system介绍

在Linux中,`exec`命令用于在当前进程中执行一个新的程序。它会取代当前进程的内容,并用新的程序来替换它。`exec`命令接受两个参数,第一个参数是要执行的程序的路径,第二个参数是一个字符串数组,用于传递给新程序的命令行参数。

`system`命令也用于在当前进程中执行一个新的程序,但它是通过调用shell来实现的。`system`命令接受一个字符串参数,该字符串包含要执行的命令。它会创建一个新的shell进程,并在该进程中执行指定的命令。

`exec`和`system`的主要区别在于它们的实现方式和用途。`exec`直接在当前进程中执行一个新程序,而`system`通过调用shell来执行命令。因此,`exec`更加高效,因为它避免了创建新的进程和shell的开销。另外,`exec`通常用于在当前进程中执行其他可执行程序,而`system`则更适用于执行shell命令和脚本。exec是一系列函数接口的总称,其实分为多个函数接口版本。

exec族函数:

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

如何选择

在Linux中,exec和system是两个不同的命令,用于执行外部程序。

exec是一个系统调用,它可以用来执行一个新的程序,并替换当前进程的内容。它需要提供一个可执行文件的路径以及命令行参数,然后它会将当前进程替换为指定的程序。execvp命令是一个低级别的命令,它可以更好地控制执行的过程,但是它不会创建新的进程。

system是一个库函数,它可以用来执行一个命令。它接收一个字符串参数,该参数是要执行的命令,然后它会创建一个新的进程来执行该命令。system命令是一个高级别的命令,它更简单易用,但是它的控制能力较弱。 

选择使用exec还是system取决于你的需求。如果你需要更细粒度的控制可以使用exec。例如如果你需要替换当前进程的内容,或者需要在子进程中执行一些特定的操作,那么exec可能更适合。另一方面,如果你只是简单地执行一个命令,并希望获得执行结果,那么system可能更方便。

void set_gpio64_low(void)
{	
	system("echo 64 > /sys/class/gpio/export");
	system("echo out > /sys/class/gpio/gpio64/direction");
	system("echo 0 > /sys/class/gpio/gpio64/value");
}

`exec`命令的基本用法

#include <unistd.h>

int execvp(const char *file, char *const argv[]);

要执行一个shell脚本,可以将shell解释器的路径作为第一个参数,将脚本文件的路径作为第二个参数,并将其他参数作为字符串数组传递。

下面是一个示例,演示如何使用`execvp`命令执行一个shell脚本:

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

int main() {
    char *const argv[] = {"./script.sh", NULL};
    execvp("/bin/sh", argv);
    printf("execvp failed\n");
    return 0;
}

在上面的示例中,`./script.sh`是要执行的shell脚本的路径。`/bin/sh`是shell解释器的路径。`NULL`表示参数数组的结束。

请注意,`execvp`命令执行成功后,当前进程将被替换为新的程序,因此后续代码不会被执行。如果`execvp`命令执行失败,它将返回-1,并且可以使用`perror`函数打印错误信息。

确保在执行`execvp`命令之前,脚本文件具有执行权限。可以使用`chmod`命令为脚本文件添加执行权限。

`execvp`命令执行成功后的当前进程将被替换为新的程序,后续代码不会被执行。如果想要在`execvp`命令执行后继续执行代码,可以使用`fork`函数创建一个子进程,在子进程中调用`execvp`命令,而父进程则可以继续执行后续代码。

下面是一个示例代码:

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

int main() {
    pid_t pid = fork();
    if (pid == 0) {
        // 子进程中执行新的程序
        char *args[] = {"ls", "-l", NULL};
        execvp("ls", args);
    } else if (pid > 0) {
        // 父进程中继续执行后续代码
        printf("This is the parent process.\n");
        // 可以添加其他代码
    } else {
        // fork失败
        printf("Fork failed.\n");
        return 1;
    }

    return 0;
}

在上述代码中,子进程中调用了`execvp`命令来执行`ls -l`命令,而父进程则继续执行后续代码。

如果你想在应用程序中满足条件时调用其他应用程序,可以考虑使用fork和execvp的组合。使用fork创建一个子进程,在子进程中使用execvp执行其他应用程序,这样可以避免替换当前进程,同时在父进程中可以继续执行后续代码。

system与execl的区别

system会新起一个子进程来调用要执行的命令。而exec只是用另一个新程序替换了当前进程的正文、数据、堆和栈段。

int system(const char * cmdstring){
    pid_t pid;
    int status;
    if(cmdstring == NULL){
        return (1);
    }
    if((pid = fork())<0){
        status = -1;
    }else if(pid == 0){
        execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);//底层就是execl
        exit(127); //子进程正常执行则不会执行此语句
    }else{
     while(waitpid(pid, &status, 0) < 0){
          if(errno != EINTER){
              status = -1;
              break;
          }
     }
    }
    return status;
}

正确处理 execvp 函数调用错误方案和相应的输出消息

需要注意的是,exec 系列函数只有在发生错误时才会返回,所以要实现错误检查例程,并根据需要处理相应的代码路径。
其中 execvp 在失败时返回 -1,而且它还会设置 errno 变量。不过要注意,errno 应该在函数调用前明确设置为 0,只有在给定的调用返回后才检查该值。execvp 函数可以接受没有斜线的文件名,这意味着文件是在 PATH 环境变量指定的目录中搜索的。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int main(void) {
    const char *args[] = { "vim", "/home/ben/tmp3.txt", NULL };
    execvp("vim", args);
    exit(EXIT_SUCCESS);
}

假设用户需要创建一个新的进程,并执行给定的程序代码,那么在这种情况下我们可以利用 fork 函数调用与 execvp 相结合。在这种情况下,我们可以利用 fork 函数调用与 execvp 相结合。fork 复制调用的进程,并创建一个新的进程,称为-子进程。在下面的例子中,我们实现了一个自定义函数包装器来创建一个新的进程并加载/执行给定的程序代码。注意,一旦创建了子进程,它就会执行不同的代码,而父进程则会等待,直到子进程退出。

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

pid_t spawnChild(const char* program, char** arg_list)
{
    pid_t ch_pid = fork();
    if (ch_pid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    if (ch_pid > 0) {
        printf("spawn child with pid - %d\n", ch_pid);
        return ch_pid;
    } else {
        execvp(program, arg_list);
        perror("execve");
        exit(EXIT_FAILURE);
    }
}

int main(void) {

    const char *args[] = { "vim", "/home/ben/tmp3.txt", NULL };
    pid_t child;
    int wstatus;
    child = spawnChild("vim", args);
    if (waitpid(child, &wstatus, WUNTRACED | WCONTINUED) == -1) {
        perror("waitpid");
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}

其他资源

Linux -- system、.(source)、exec的区别_青椒*^_^*凤爪爪的博客-CSDN博客

exec和system函数_execl system_Lawrence_121的博客-CSDN博客

Linux -- system、.(source)、exec的区别_青椒*^_^*凤爪爪的博客-CSDN博客

exec族函数、system()函数和popen函数_exec函数 system_基尔霍夫原来是码农的博客-CSDN博客 https://www.cnblogs.com/armsom/articles/17523386.html

Linux下对GPIO的操作控制(基于GPIO子系统)_linux 通过按钮控制gpio de_金城孤客的博客-CSDN博客 Linux系统应用层GPIO控制_echo 268 > export增加gpio268_技术の宅的博客-CSDN博客

猜你喜欢

转载自blog.csdn.net/qq8864/article/details/131957022