The system() Function in C++

Jinku Hu Oct 12, 2023
  1. Use the system() Function in C++ to Execution Shell Command
  2. Use system(nullptr) to Check if Shell Is Available on the System
  3. Use wstatus Macros to Check the Status of Executed Command
The system() Function in C++

This article will demonstrate multiple methods of using a library function - system() in C++.

Use the system() Function in C++ to Execution Shell Command

The system() function has been part of the C standard library for a while, and it can be included in C++ code as well without extra libraries. The function is used to execute a shell command from the calling process. Note though, system is created for special use cases when the calling program needs to spawn a single child process and immediately start waiting for its termination. Thus, the function itself is implemented with multiple system calls that are available as a part of the system interface.

If we assume the UNIX environment, the user does not have to deal directly with fork, exec, and wait functions that control a new process creation/cleanup. The following example demonstrates the simplest use case for the system function, which executes the ls command-line utility to print the files in the current working directory.

#include <iostream>

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

  return EXIT_SUCCESS;
}

The system() function usually creates two processes to execute a single command. Namely, it creates a shell with one exec call and another one for the given command that the shell will execute. It negatively affects the performance relative to directly using the underlying system calls. Notice that if we run the top command with system, the program is waiting until the user exits top manually, which will return in the calling process and force it to move to the return statement as shown in the following example.

#include <iostream>

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

  return EXIT_SUCCESS;
}

Use system(nullptr) to Check if Shell Is Available on the System

The system() function takes a single character string as the argument, which is the command that needs to be run from the shell. If we pass it nullptr or NULL, a nonzero value is returned when a shell program is available on the system, or if the zero is returned, it indicates that the shell is not available.

#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;
}

Output:

shell is available on the system!

Use wstatus Macros to Check the Status of Executed Command

If the system call fails to create a child process, it returns -1 and sets errno accordingly. If the function call is successful, the return value is the termination status code of the shell that executed the given command. Also, this termination status code is the same as the exit code of the last command that was executed. Thus, one can examine its value using the wstatus macros described in the wait system call man page. The next code snippet implements a printWaitStatus function to check the system return value and print the details about the last command that was executed.

#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;
}

Output:

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

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook