如何使用参数在linux中的C代码中执行外部程序?

js0*_*823 47 c linux

我想在C代码中执行另一个程序.例如,我想执行一个命令

./foo 1 2 3
Run Code Online (Sandbox Code Playgroud)

foo是存在于同一文件夹中的程序,并且1 2 3是参数. foo程序创建一个将在我的代码中使用的文件.

我该怎么做呢?

Eri*_*rik 43

一个简单的方法,使用system():

#include <stdlib.h>
...
int status = system("./foo 1 2 3");
Run Code Online (Sandbox Code Playgroud)

system()将等待foo完成执行,然后返回一个状态变量,你可以用来检查例如exitcode(命令的exitcode乘以256,所以除以system()的返回值得到实际的exitcode:)int exitcode = status / 256.

wait()(在第2部分,man 2 waitLinux系统上)的联机帮助页列出了可用于检查状态的各种宏,最有趣的是WIFEXITEDWEXITSTATUS.

或者,如果你需要读取foo的标准输出,请使用popen(3),它返回一个文件指针(FILE *); 与命令的标准输入/输出交互与读取或写入文件相同.

  • 此解决方案不是正确的方法,您可以在应用程序中引入许多安全漏洞.检查一下:https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId = 2130132更好的解决方案是使用popen,或execve或相关功能. (7认同)
  • stdlib.h,在另一个答案中找到. (5认同)
  • 请参阅https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=2130132以及该作者发布的替代答案. (2认同)

Jon*_*ham 35

system函数调用shell来运行该命令.虽然这很方便,但它具有众所周知的安全隐患.如果您可以完全指定要执行的程序或脚本的路径,并且可以承受失去所system提供的平台独立性,那么您可以使用下面函数中所示的execve包装器exec_prog来更安全地执行您的程序.

以下是在调用者中指定参数的方法:

const char    *my_argv[64] = {"/foo/bar/baz" , "-foo" , "-bar" , NULL};
Run Code Online (Sandbox Code Playgroud)

然后exec_prog像这样调用函数:

int rc = exec_prog(my_argv);
Run Code Online (Sandbox Code Playgroud)

这是exec_prog功能:

static int exec_prog(const char **argv)
{
    pid_t   my_pid;
    int     status, timeout /* unused ifdef WAIT_FOR_COMPLETION */;

    if (0 == (my_pid = fork())) {
            if (-1 == execve(argv[0], (char **)argv , NULL)) {
                    perror("child process execve failed [%m]");
                    return -1;
            }
    }

#ifdef WAIT_FOR_COMPLETION
    timeout = 1000;

    while (0 == waitpid(my_pid , &status , WNOHANG)) {
            if ( --timeout < 0 ) {
                    perror("timeout");
                    return -1;
            }
            sleep(1);
    }

    printf("%s WEXITSTATUS %d WIFEXITED %d [status %d]\n",
            argv[0], WEXITSTATUS(status), WIFEXITED(status), status);

    if (1 != WIFEXITED(status) || 0 != WEXITSTATUS(status)) {
            perror("%s failed, halt system");
            return -1;
    }

#endif
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

记住包括:

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
Run Code Online (Sandbox Code Playgroud)

有关需要通过文件描述符(如和)与已执行程序进行通信的情况,请参阅相关的SE帖子.stdinstdout

  • `%s` 和 `%m` 在 `perror` 调用中做了什么?这不是一个错误吗? (2认同)

Ped*_*ves 17

您可以使用fork(),system()以便您的程序不必等到system()返回.

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

int main(int argc,char* argv[]){

    int status;

    // By calling fork(), a child process will be created as a exact duplicate of the calling process.
    // Search for fork() (maybe "man fork" on Linux) for more information.
    if(fork() == 0){ 
        // Child process will return 0 from fork()
        printf("I'm the child process.\n");
        status = system("my_app");
        exit(0);
    }else{
        // Parent process will return a non-zero value from fork()
        printf("I'm the parent.\n");
    }

    printf("This is my main program and it will continue running and doing anything i want to...\n");

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 仅使用子进程中的execl或execv会更有效率,因为它不会使用外壳程序,也不会派生新线程,并且无论如何您都将在调用system之后退出。另外,如果您不调用wait(),则该过程将成为僵尸。 (2认同)

Bil*_*lly 6

system()执行一个 shell,然后负责解析参数并执行所需的程序。要直接执行程序,请使用 fork() 和 exec()(这是 system() 用于执行 shell 以及 shell 本身用于执行命令的内容)。

#include <unistd.h>

int main() {
     if (fork() == 0) {
          /*
           * fork() returns 0 to the child process
           * and the child's PID to the parent.
           */
          execl("/path/to/foo", "foo", "arg1", "arg2", "arg3", 0);
          /*
           * We woundn't still be here if execl() was successful,
           * so a non-zero exit value is appropriate.
           */
          return 1;
     }

     return 0;
}
Run Code Online (Sandbox Code Playgroud)


Fre*_*Foo 5

在C中

#include <stdlib.h>

system("./foo 1 2 3");
Run Code Online (Sandbox Code Playgroud)

在 C++ 中

#include <cstdlib>

std::system("./foo 1 2 3");
Run Code Online (Sandbox Code Playgroud)

然后照常打开并读取文件。