C++ の system()関数
- 
          
            C++ の system()関数を使用してシェルコマンドを実行する
- 
          
            システムで system(nullptr)を使用してシェルが使用可能かどうかを確認する
- 
          
            wstatusマクロを使用して、実行されたコマンドのステータスを確認する
 
この記事では、C++ でライブラリ関数 system() を使用する複数の方法について説明します。
C++ の system() 関数を使用してシェルコマンドを実行する
    
system() 関数はしばらくの間 C 標準ライブラリの一部であり、追加のライブラリなしで C++ コードに含めることもできます。この関数は、呼び出しプロセスからシェルコマンドを実行するために使用されます。ただし、システムは、呼び出し元のプログラムが単一の子プロセスを生成し、すぐにその終了を待機し始める必要がある特別なユースケースのために作成されていることに注意してください。したがって、関数自体は、システムインターフェイスの一部として使用できる複数のシステムコールで実装されます。
UNIX 環境を想定している場合、ユーザーは、新しいプロセスの作成/クリーンアップを制御する fork、exec、および wait 関数を直接処理する必要はありません。次の例は、system 関数の最も単純な使用例を示しています。この関数は、ls コマンドラインユーティリティを実行して、現在の作業ディレクトリにあるファイルを出力します。
#include <iostream>
int main() {
  system("ls");
  return EXIT_SUCCESS;
}
system() 関数は通常、1つのコマンドを実行するために 2つのプロセスを作成します。つまり、シェルが実行する特定のコマンドに対して、1つの exec 呼び出しと別の呼び出しでシェルを作成します。基盤となるシステムコールを直接使用する場合に比べて、パフォーマンスに悪影響を及ぼします。system で top コマンドを実行すると、プログラムはユーザーが手動で top を終了するまで待機します。これにより、呼び出しプロセスに戻り、に示すように強制的に return ステートメントに移動します。次の例。
#include <iostream>
int main() {
  system("top");
  return EXIT_SUCCESS;
}
システムで system(nullptr) を使用してシェルが使用可能かどうかを確認する
system() 関数は、引数として 1 文字の文字列を取ります。これは、シェルから実行する必要のあるコマンドです。nullptr または NULL を渡すと、システムでシェルプログラムが使用可能になったときにゼロ以外の値が返されます。ゼロが返された場合は、シェルが使用できないことを示します。
#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 を設定します。関数呼び出しが成功した場合、戻り値は、指定されたコマンドを実行したシェルの終了ステータスコードです。また、この終了ステータスコードは、最後に実行されたコマンドの終了コードと同じです。したがって、wait システムコール man ページで説明されている 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
