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