C++ 中的 system() 函数

Jinku Hu 2023年10月12日
  1. 在 C++ 中使用 system() 函数来执行 Shell 命令
  2. 使用 system(nullptr) 检查系统上的 Shell 是否可用
  3. 使用 wstatus 宏检查已执行命令的状态
C++ 中的 system() 函数

本文将演示在 C++ 中使用库函数的多种方法 - system()

在 C++ 中使用 system() 函数来执行 Shell 命令

system() 函数作为 C 标准库的一部分已经有一段时间了,它也可以包含在 C++ 代码中,而无需额外的库。该函数用于从调用进程执行 shell 命令。但请注意,当调用程序需要生成单个子进程并立即开始等待其终止时,为特殊用例创建 system。因此,函数本身是通过多个系统调用来实现的,这些系统调用可作为系统接口的一部分使用。

如果我们假设 UNIX 环境,用户不必直接处理控制新进程创建/清理的 forkexecwait 函数。以下示例演示了 system 函数的最简单用例,该函数执行 ls 命令行实用程序以打印当前工作目录中的文件。

#include <iostream>

int main() {
  system("ls");

  return EXIT_SUCCESS;
}

system() 函数通常会创建两个进程来执行单个命令。也就是说,它创建了一个带有一个 exec 调用的 shell,另一个用于 shell 将执行的给定命令。相对于直接使用底层系统调用而言,它会对性能产生负面影响。请注意,如果我们使用 system 运行 top 命令,程序会等待直到用户手动退出 top,这将在调用过程中返回并强制它移动到 return 语句,如下面的例子。

#include <iostream>

int main() {
  system("top");

  return EXIT_SUCCESS;
}

使用 system(nullptr) 检查系统上的 Shell 是否可用

system() 函数以单个字符串作为参数,这是需要从 shell 运行的命令。如果我们传递给它 nullptrNULL,当 shell 程序在系统上可用时返回一个非零值,或者如果返回零,则表明 shell 不可用。

#include <iostream>
#include <string>

using std::cout;
using std::endl;

int main() {
  auto ret = system(nullptr);
  if (ret != 0)
    cout << "shell is available on the system!" << endl;
  else
    cout << "shell is not available on the system!" << endl;

  return EXIT_SUCCESS;
}

输出:

shell is available on the system!

使用 wstatus 宏检查已执行命令的状态

如果 system 调用未能创建子进程,它将返回 -1 并相应地设置 errno。如果函数调用成功,则返回值是执行给定命令的 shell 的终止状态代码。此外,此终止状态代码与执行的最后一个命令的退出代码相同。因此,可以使用 wait 系统调用手册页中描述的 wstatus 宏检查其值。下一个代码片段实现了一个 printWaitStatus 函数来检查 system 返回值并打印有关执行的最后一个命令的详细信息。

#include <cstring>
#include <iostream>
#include <string>

using std::cin;
using std::cout;
using std::endl;
using std::string;

void printWaitStatus(const char *msg, int status) {
  if (msg != nullptr) printf("%s", msg);

  if (WIFEXITED(status)) {
    printf("child exited, status=%d\n", WEXITSTATUS(status));
  } else if (WIFSIGNALED(status)) {
    printf("child killed by signal %d (%s)", WTERMSIG(status),
           strsignal(WTERMSIG(status)));
#ifdef WCOREDUMP
    if (WCOREDUMP(status)) printf(" (core dumped)");
#endif
    printf("\n");
  } else if (WIFSTOPPED(status)) {
    printf("child stopped by signal %d (%s)\n", WSTOPSIG(status),
           strsignal(WSTOPSIG(status)));
#ifdef WIFCONTINUED
  } else if (WIFCONTINUED(status)) {
    printf("child continued\n");
#endif
  } else {
    printf("status=%x\n", (unsigned int)status);
  }
}

int main() {
  auto ret = system("ls");

  if (ret == -1)
    cout << "a child process could not be created, or"
            "its status could not be retrieved!"
         << endl;
  else
    printWaitStatus(nullptr, ret);

  return EXIT_SUCCESS;
}

输出:

(ls command output)
...
child exited, status=0
作者: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

DelftStack.com 创始人。Jinku 在机器人和汽车行业工作了8多年。他在自动测试、远程测试及从耐久性测试中创建报告时磨练了自己的编程技能。他拥有电气/电子工程背景,但他也扩展了自己的兴趣到嵌入式电子、嵌入式编程以及前端和后端编程。

LinkedIn Facebook