Comment exécuter une commande et obtenir la sortie de la commande dans C ++ à l'aide de POSIX?

463

Je cherche un moyen d'obtenir la sortie d'une commande lorsqu'elle est exécutée à partir d'un programme C ++. J'ai regardé en utilisant la system()fonction, mais cela exécutera juste une commande. Voici un exemple de ce que je recherche:

std::string result = system("./some_command");

J'ai besoin d'exécuter une commande arbitraire et d'obtenir sa sortie. J'ai regardé boost.org , mais je n'ai rien trouvé qui puisse me donner ce dont j'ai besoin.

Misha M
la source
Voir également les réponses à cette question: /programming/52164723/how-to-execute-a-command-and-get-return-code-stdout-and-stderr-of-command-in-cpour une extension de la grande réponse ci-dessous qui fournit des méthodes pour obtenir le return codeet stderrainsi que stdoutque cette réponse explique déjà
code_fodder
2
@code_fodder vous pouvez créer un lien vers stackoverflow.com/questions/52164723/…
Jonas Stein

Réponses:

600
#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <array>

std::string exec(const char* cmd) {
    std::array<char, 128> buffer;
    std::string result;
    std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
    if (!pipe) {
        throw std::runtime_error("popen() failed!");
    }
    while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
        result += buffer.data();
    }
    return result;
}

Version pré-C ++ 11:

#include <iostream>
#include <stdexcept>
#include <stdio.h>
#include <string>

std::string exec(const char* cmd) {
    char buffer[128];
    std::string result = "";
    FILE* pipe = popen(cmd, "r");
    if (!pipe) throw std::runtime_error("popen() failed!");
    try {
        while (fgets(buffer, sizeof buffer, pipe) != NULL) {
            result += buffer;
        }
    } catch (...) {
        pclose(pipe);
        throw;
    }
    pclose(pipe);
    return result;
}

Remplacez popenet pclosepar _popenet _pclosepour Windows.

waqas
la source
70
Sachez que cela ne saisira que stdout et non stderr .
kalaxy
14
Sachez également qu'une exception peut se produire result += buffer, de sorte que le tuyau peut ne pas être correctement fermé.
Fred Foo
6
@Yasky: Lorsque le programme en cours d'exécution est int main(){ puts("ERROR"); }.
dreamlax
8
La réponse est bonne mais il serait préférable de remplacer 'char * cmd' par 'const char * cmd'
fnc12
29
unique_ptr est un meilleur ajustement ici, où le compte de référence réel n'est jamais utilisé.
Czipperz
77

Obtenir à la fois stdout et stderr (et aussi écrire dans stdin, non illustré ici) est facile avec mon en - tête pstreams , qui définit les classes iostream qui fonctionnent comme popen:

#include <pstream.h>
#include <string>
#include <iostream>

int main()
{
  // run a process and create a streambuf that reads its stdout and stderr
  redi::ipstream proc("./some_command", redi::pstreams::pstdout | redi::pstreams::pstderr);
  std::string line;
  // read child's stdout
  while (std::getline(proc.out(), line))
    std::cout << "stdout: " << line << '\n';
  # if reading stdout stopped at EOF then reset the state:
  if (proc.eof() && proc.fail())
    proc.clear();
  // read child's stderr
  while (std::getline(proc.err(), line))
    std::cout << "stderr: " << line << '\n';
} 
Jonathan Wakely
la source
18
Je ne suis pas d'accord. popenvous oblige à utiliser l'API C stdio, je préfère l'API iostreams. popenvous oblige à nettoyer manuellement la FILEpoignée, les pstreams le font automatiquement. popenaccepte uniquement un const char*pour l'argument, qui nécessite des précautions pour éviter les attaques par injection de shell, pstreams vous permet de passer un vecteur de chaînes similaire à execv, ce qui est plus sûr. popenne vous donne rien d'autre qu'un tuyau, pstreams vous indique le PID de l'enfant vous permettant d'envoyer des signaux, par exemple pour le tuer s'il est bloqué ou s'il ne sort pas. Ce sont tous des avantages même si vous ne souhaitez que des E / S unidirectionnelles.
Jonathan Wakely
1
Un autre problème avec cette solution est si l'enfant écrit suffisamment sur stderr pour remplir les tampons et bloquer avant de commencer à écrire sur stdout. Le parent bloquera la lecture de stdout, tandis que l'enfant est bloqué en attendant que stderr soit lu. blocage des ressources! Au moins une de ces boucles serait mieux asynchrone (c'est-à-dire filetée).
Jesse Chisholm
1
@JesseChisholm, oui, cela pourrait être un problème. Mais vous n'avez pas besoin d'utiliser de threads car pstreams permet une approximation des E / S non bloquantes à l'aide de l'interface iostream, en utilisant spécifiquement la fonction readsome , qui vérifie la disponibilité à l'aide pstreambuf::in_avail(), donc ne bloquera pas. Cela permet de démultiplexer les sorties standard et stderr du processus car chacun dispose de données. pstreambuf::in_avail()ne fonctionne à 100% de manière fiable que si le système d'exploitation prend en charge l'ioctl FIONREAD non standard, mais qui est pris en charge sur (au moins) GNU / Linux et Solaris.
Jonathan Wakely
13
@chiliNUT la nouvelle version 1.0.1 utilise la licence Boost.
Jonathan Wakely
1
@JonathanWakely comment puis-je tuer l'ipstream après disons un délai de 5 secondes?
AK
34

J'utiliserais popen () (++ waqas) .

Mais parfois, il faut lire et écrire ...

Il semble que plus personne ne fasse les choses à la dure.

(En supposant un environnement Unix / Linux / Mac, ou peut-être Windows avec une couche de compatibilité POSIX ...)

enum PIPE_FILE_DESCRIPTERS
{
  READ_FD  = 0,
  WRITE_FD = 1
};

enum CONSTANTS
{
  BUFFER_SIZE = 100
};

int
main()
{
  int       parentToChild[2];
  int       childToParent[2];
  pid_t     pid;
  string    dataReadFromChild;
  char      buffer[BUFFER_SIZE + 1];
  ssize_t   readResult;
  int       status;

  ASSERT_IS(0, pipe(parentToChild));
  ASSERT_IS(0, pipe(childToParent));

  switch (pid = fork())
  {
    case -1:
      FAIL("Fork failed");
      exit(-1);

    case 0: /* Child */
      ASSERT_NOT(-1, dup2(parentToChild[READ_FD], STDIN_FILENO));
      ASSERT_NOT(-1, dup2(childToParent[WRITE_FD], STDOUT_FILENO));
      ASSERT_NOT(-1, dup2(childToParent[WRITE_FD], STDERR_FILENO));
      ASSERT_IS(0, close(parentToChild [WRITE_FD]));
      ASSERT_IS(0, close(childToParent [READ_FD]));

      /*     file, arg0, arg1,  arg2 */
      execlp("ls", "ls", "-al", "--color");

      FAIL("This line should never be reached!!!");
      exit(-1);

    default: /* Parent */
      cout << "Child " << pid << " process running..." << endl;

      ASSERT_IS(0, close(parentToChild [READ_FD]));
      ASSERT_IS(0, close(childToParent [WRITE_FD]));

      while (true)
      {
        switch (readResult = read(childToParent[READ_FD],
                                  buffer, BUFFER_SIZE))
        {
          case 0: /* End-of-File, or non-blocking read. */
            cout << "End of file reached..."         << endl
                 << "Data received was ("
                 << dataReadFromChild.size() << "): " << endl
                 << dataReadFromChild                << endl;

            ASSERT_IS(pid, waitpid(pid, & status, 0));

            cout << endl
                 << "Child exit staus is:  " << WEXITSTATUS(status) << endl
                 << endl;

            exit(0);


          case -1:
            if ((errno == EINTR) || (errno == EAGAIN))
            {
              errno = 0;
              break;
            }
            else
            {
              FAIL("read() failed");
              exit(-1);
            }

          default:
            dataReadFromChild . append(buffer, readResult);
            break;
        }
      } /* while (true) */
  } /* switch (pid = fork())*/
}

Vous pouvez également vouloir jouer avec les lectures select () et non bloquantes.

fd_set          readfds;
struct timeval  timeout;

timeout.tv_sec  = 0;    /* Seconds */
timeout.tv_usec = 1000; /* Microseconds */

FD_ZERO(&readfds);
FD_SET(childToParent[READ_FD], &readfds);

switch (select (1 + childToParent[READ_FD], &readfds, (fd_set*)NULL, (fd_set*)NULL, & timeout))
{
  case 0: /* Timeout expired */
    break;

  case -1:
    if ((errno == EINTR) || (errno == EAGAIN))
    {
      errno = 0;
      break;
    }
    else
    {
      FAIL("Select() Failed");
      exit(-1);
    }

  case 1:  /* We have input */
    readResult = read(childToParent[READ_FD], buffer, BUFFER_SIZE);
    // However you want to handle it...
    break;

  default:
    FAIL("How did we see input on more than one file descriptor?");
    exit(-1);
}
Mr.Ree
la source
1
La manière la plus difficile est la bonne :) J'aime l'idée avec l'appel select (), bien que dans ce cas, je doive attendre la fin de la tâche. Je garderai ce code pour un autre projet que j'ai :)
Misha M
4
... ou vous pouvez utiliser la fonction posix_spawnp existante
Per Johansson
5
Votre execlpappel a un bug: le dernier argpointeur passé doit être (char *) NULLpour terminer correctement la liste des arguments variadiques (voir execlp(3)pour référence).
Kristóf Marussy
Est-ce que cela fonctionnera sur unix, linux et windows? Pouvez-vous également plaire aux fichiers d'en-tête?
kittu
Où passez-vous le fichier .bat dans le code?
kittu
33

Pour Windows, popenfonctionne également, mais il ouvre une fenêtre de console - qui clignote rapidement sur votre application d'interface utilisateur. Si vous voulez être un professionnel, il est préférable de désactiver ce "clignotant" (surtout si l'utilisateur final peut l'annuler).

Voici donc ma propre version pour Windows:

(Ce code est partiellement recombiné à partir d'idées écrites dans les exemples The Code Project et MSDN.)

#include <windows.h>
#include <atlstr.h>
//
// Execute a command and get the results. (Only standard output)
//
CStringA ExecCmd(
    const wchar_t* cmd              // [in] command to execute
)
{
    CStringA strResult;
    HANDLE hPipeRead, hPipeWrite;

    SECURITY_ATTRIBUTES saAttr = {sizeof(SECURITY_ATTRIBUTES)};
    saAttr.bInheritHandle = TRUE; // Pipe handles are inherited by child process.
    saAttr.lpSecurityDescriptor = NULL;

    // Create a pipe to get results from child's stdout.
    if (!CreatePipe(&hPipeRead, &hPipeWrite, &saAttr, 0))
        return strResult;

    STARTUPINFOW si = {sizeof(STARTUPINFOW)};
    si.dwFlags     = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    si.hStdOutput  = hPipeWrite;
    si.hStdError   = hPipeWrite;
    si.wShowWindow = SW_HIDE; // Prevents cmd window from flashing.
                              // Requires STARTF_USESHOWWINDOW in dwFlags.

    PROCESS_INFORMATION pi = { 0 };

    BOOL fSuccess = CreateProcessW(NULL, (LPWSTR)cmd, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
    if (! fSuccess)
    {
        CloseHandle(hPipeWrite);
        CloseHandle(hPipeRead);
        return strResult;
    }

    bool bProcessEnded = false;
    for (; !bProcessEnded ;)
    {
        // Give some timeslice (50 ms), so we won't waste 100% CPU.
        bProcessEnded = WaitForSingleObject( pi.hProcess, 50) == WAIT_OBJECT_0;

        // Even if process exited - we continue reading, if
        // there is some data available over pipe.
        for (;;)
        {
            char buf[1024];
            DWORD dwRead = 0;
            DWORD dwAvail = 0;

            if (!::PeekNamedPipe(hPipeRead, NULL, 0, NULL, &dwAvail, NULL))
                break;

            if (!dwAvail) // No data available, return
                break;

            if (!::ReadFile(hPipeRead, buf, min(sizeof(buf) - 1, dwAvail), &dwRead, NULL) || !dwRead)
                // Error, the child process might ended
                break;

            buf[dwRead] = 0;
            strResult += buf;
        }
    } //for

    CloseHandle(hPipeWrite);
    CloseHandle(hPipeRead);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    return strResult;
} //ExecCmd
TarmoPikaro
la source
1
Ceci est ma solution préférée pour Windows, j'espère que vous pardonnez mes modifications. Je suggérerais de rendre la const-cast plus explicite, alors que je considère l'utilisation explicite de wchar_tet CreateProcessWcomme une restriction inutile.
Wolf
Voyez-vous un problème ou un problème potentiel avec cette distribution? Je préfère garder le code au minimum et ne pas l'écrire sans besoin.
TarmoPikaro
4
Après avoir lu la fonction CreateProcess (Windows) , je vois un réel danger à faire ceci: The Unicode version of this function, CreateProcessW, can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter is a constant string, the function may cause an access violation.il est donc peut-être préférable de copier la ligne de commande dans un tampon séparé d'abord, pour empêcher l'appelant de changer son entrée d'origine.
Wolf
Cette réponse ne gère pas correctement stderr.
Refael Sheinker le
Cela fonctionne-t-il également pour les systèmes Unix? Ou devrais-je utiliser autre chose pour un périphérique Unix?
255.tar.xz
17

Deux approches possibles:

  1. Je ne pense pas que cela popen()fasse partie de la norme C ++ (cela fait partie de POSIX de la mémoire), mais il est disponible sur tous les UNIX avec lesquels j'ai travaillé (et vous semblez viser UNIX depuis que votre commande l'est ./some_command).

  2. Au cas où il n'y en aurait pas popen(), vous pouvez utiliser system("./some_command >/tmp/some_command.out");, puis utiliser les fonctions d'E / S normales pour traiter le fichier de sortie.

paxdiablo
la source
Merci pour popen, je vais l'utiliser pour l'instant et je m'inquiéterai des systèmes non POSIX si cela se produit.
Misha M
8

Ce qui suit pourrait être une solution portable. Il suit les normes.

#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <sstream>

std::string ssystem (const char *command) {
    char tmpname [L_tmpnam];
    std::tmpnam ( tmpname );
    std::string scommand = command;
    std::string cmd = scommand + " >> " + tmpname;
    std::system(cmd.c_str());
    std::ifstream file(tmpname, std::ios::in | std::ios::binary );
    std::string result;
    if (file) {
        while (!file.eof()) result.push_back(file.get())
            ;
        file.close();
    }
    remove(tmpname);
    return result;
}

// For Cygwin

int main(int argc, char *argv[])
{
    std::string bash = "FILETWO=/cygdrive/c/*\nfor f in $FILETWO\ndo\necho \"$f\"\ndone ";
    std::string in;
    std::string s = ssystem(bash.c_str());
    std::istringstream iss(s);
    std::string line;
    while (std::getline(iss, line))
    {
        std::cout << "LINE-> " + line + "  length: " << line.length() << std::endl;
    }
    std::cin >> in;
    return 0;
}
hanshenrik
la source
4
J'obtiens cet avertissement avec gcc: "avertissement: l'utilisation de tmpnamest dangereuse, mieux vaut l'utiliser mkstemp"
Mark Lakata
8

Je n'ai pas pu comprendre pourquoi popen / pclose est absent de Code :: Blocks / MinGW. J'ai donc contourné le problème en utilisant CreateProcess () et CreatePipe () à la place.

Voici la solution qui a fonctionné pour moi:

//C++11
#include <cstdio>
#include <iostream>
#include <windows.h>
#include <cstdint>
#include <deque>
#include <string>
#include <thread>

using namespace std;

int SystemCapture(
    string         CmdLine,    //Command Line
    string         CmdRunDir,  //set to '.' for current directory
    string&        ListStdOut, //Return List of StdOut
    string&        ListStdErr, //Return List of StdErr
    uint32_t&      RetCode)    //Return Exit Code
{
    int                  Success;
    SECURITY_ATTRIBUTES  security_attributes;
    HANDLE               stdout_rd = INVALID_HANDLE_VALUE;
    HANDLE               stdout_wr = INVALID_HANDLE_VALUE;
    HANDLE               stderr_rd = INVALID_HANDLE_VALUE;
    HANDLE               stderr_wr = INVALID_HANDLE_VALUE;
    PROCESS_INFORMATION  process_info;
    STARTUPINFO          startup_info;
    thread               stdout_thread;
    thread               stderr_thread;

    security_attributes.nLength              = sizeof(SECURITY_ATTRIBUTES);
    security_attributes.bInheritHandle       = TRUE;
    security_attributes.lpSecurityDescriptor = nullptr;

    if (!CreatePipe(&stdout_rd, &stdout_wr, &security_attributes, 0) ||
            !SetHandleInformation(stdout_rd, HANDLE_FLAG_INHERIT, 0)) {
        return -1;
    }

    if (!CreatePipe(&stderr_rd, &stderr_wr, &security_attributes, 0) ||
            !SetHandleInformation(stderr_rd, HANDLE_FLAG_INHERIT, 0)) {
        if (stdout_rd != INVALID_HANDLE_VALUE) CloseHandle(stdout_rd);
        if (stdout_wr != INVALID_HANDLE_VALUE) CloseHandle(stdout_wr);
        return -2;
    }

    ZeroMemory(&process_info, sizeof(PROCESS_INFORMATION));
    ZeroMemory(&startup_info, sizeof(STARTUPINFO));

    startup_info.cb         = sizeof(STARTUPINFO);
    startup_info.hStdInput  = 0;
    startup_info.hStdOutput = stdout_wr;
    startup_info.hStdError  = stderr_wr;

    if(stdout_rd || stderr_rd)
        startup_info.dwFlags |= STARTF_USESTDHANDLES;

    // Make a copy because CreateProcess needs to modify string buffer
    char      CmdLineStr[MAX_PATH];
    strncpy(CmdLineStr, CmdLine.c_str(), MAX_PATH);
    CmdLineStr[MAX_PATH-1] = 0;

    Success = CreateProcess(
        nullptr,
        CmdLineStr,
        nullptr,
        nullptr,
        TRUE,
        0,
        nullptr,
        CmdRunDir.c_str(),
        &startup_info,
        &process_info
    );
    CloseHandle(stdout_wr);
    CloseHandle(stderr_wr);

    if(!Success) {
        CloseHandle(process_info.hProcess);
        CloseHandle(process_info.hThread);
        CloseHandle(stdout_rd);
        CloseHandle(stderr_rd);
        return -4;
    }
    else {
        CloseHandle(process_info.hThread);
    }

    if(stdout_rd) {
        stdout_thread=thread([&]() {
            DWORD  n;
            const size_t bufsize = 1000;
            char         buffer [bufsize];
            for(;;) {
                n = 0;
                int Success = ReadFile(
                    stdout_rd,
                    buffer,
                    (DWORD)bufsize,
                    &n,
                    nullptr
                );
                printf("STDERR: Success:%d n:%d\n", Success, (int)n);
                if(!Success || n == 0)
                    break;
                string s(buffer, n);
                printf("STDOUT:(%s)\n", s.c_str());
                ListStdOut += s;
            }
            printf("STDOUT:BREAK!\n");
        });
    }

    if(stderr_rd) {
        stderr_thread=thread([&]() {
            DWORD        n;
            const size_t bufsize = 1000;
            char         buffer [bufsize];
            for(;;) {
                n = 0;
                int Success = ReadFile(
                    stderr_rd,
                    buffer,
                    (DWORD)bufsize,
                    &n,
                    nullptr
                );
                printf("STDERR: Success:%d n:%d\n", Success, (int)n);
                if(!Success || n == 0)
                    break;
                string s(buffer, n);
                printf("STDERR:(%s)\n", s.c_str());
                ListStdOut += s;
            }
            printf("STDERR:BREAK!\n");
        });
    }

    WaitForSingleObject(process_info.hProcess,    INFINITE);
    if(!GetExitCodeProcess(process_info.hProcess, (DWORD*) &RetCode))
        RetCode = -1;

    CloseHandle(process_info.hProcess);

    if(stdout_thread.joinable())
        stdout_thread.join();

    if(stderr_thread.joinable())
        stderr_thread.join();

    CloseHandle(stdout_rd);
    CloseHandle(stderr_rd);

    return 0;
}

int main()
{
    int            rc;
    uint32_t       RetCode;
    string         ListStdOut;
    string         ListStdErr;

    cout << "STARTING.\n";

    rc = SystemCapture(
        "C:\\Windows\\System32\\ipconfig.exe",    //Command Line
        ".",                                     //CmdRunDir
        ListStdOut,                              //Return List of StdOut
        ListStdErr,                              //Return List of StdErr
        RetCode                                  //Return Exit Code
    );
    if (rc < 0) {
        cout << "ERROR: SystemCapture\n";
    }

    cout << "STDOUT:\n";
    cout << ListStdOut;

    cout << "STDERR:\n";
    cout << ListStdErr;

    cout << "Finished.\n";

    cout << "Press Enter to Continue";
    cin.ignore();

    return 0;
}
Bill Moore
la source
5
Je vous remercie! Il s'agit de la meilleure implémentation popen pour Windows sur Internet! Et en passant le drapeau CREATE_NO_WINDOW, on peut enfin se débarrasser des invites cmd ennuyeuses qui apparaissent.
Lacho Tomov
1
Où passez-vous le CREATE_NO_WINDOWtruc?
Refael Sheinker le
2
@Bill Moore, si vous remarquez, il y a un bug dans votre réponse. ListStdErrn'est jamais utilisé.
Refael Sheinker le
4

En supposant POSIX, un code simple pour capturer la sortie standard:

#include <sys/wait.h>
#include <unistd.h>
#include <string>
#include <vector>

std::string qx(const std::vector<std::string>& args) {
  int stdout_fds[2];
  pipe(stdout_fds);

  int stderr_fds[2];
  pipe(stderr_fds);

  const pid_t pid = fork();
  if (!pid) {
    close(stdout_fds[0]);
    dup2(stdout_fds[1], 1);
    close(stdout_fds[1]);

    close(stderr_fds[0]);
    dup2(stderr_fds[1], 2);
    close(stderr_fds[1]);

    std::vector<char*> vc(args.size() + 1, 0);
    for (size_t i = 0; i < args.size(); ++i) {
      vc[i] = const_cast<char*>(args[i].c_str());
    }

    execvp(vc[0], &vc[0]);
    exit(0);
  }

  close(stdout_fds[1]);

  std::string out;
  const int buf_size = 4096;
  char buffer[buf_size];
  do {
    const ssize_t r = read(stdout_fds[0], buffer, buf_size);
    if (r > 0) {
      out.append(buffer, r);
    }
  } while (errno == EAGAIN || errno == EINTR);

  close(stdout_fds[0]);

  close(stderr_fds[1]);
  close(stderr_fds[0]);

  int r, status;
  do {
    r = waitpid(pid, &status, 0);
  } while (r == -1 && errno == EINTR);

  return out;
}

Les contributions de code sont les bienvenues pour plus de fonctionnalités:

https://github.com/ericcurtin/execxx

ericcurtin
la source
2

Vous pouvez obtenir la sortie après avoir exécuté un script à l'aide d'un canal. Nous utilisons des tuyaux lorsque nous voulons la sortie du processus enfant.

int my_func() {
    char ch;
    FILE *fpipe;
    FILE *copy_fp;
    FILE *tmp;
    char *command = (char *)"/usr/bin/my_script my_arg";
    copy_fp = fopen("/tmp/output_file_path", "w");
    fpipe = (FILE *)popen(command, "r");
    if (fpipe) {
        while ((ch = fgetc(fpipe)) != EOF) {
            fputc(ch, copy_fp);
        }
    }
    else {
        if (copy_fp) {
            fprintf(copy_fp, "Sorry there was an error opening the file");
        }
    }
    pclose(fpipe);
    fclose(copy_fp);
    return 0;
}

Voici donc le script que vous souhaitez exécuter. Mettez-le dans une variable de commande avec les arguments pris par votre script (rien si aucun argument). Et le fichier où vous souhaitez capturer la sortie du script, placez-le dans copy_fp.

Ainsi, le popen exécute votre script et met la sortie dans fpipe, puis vous pouvez simplement tout copier de cela dans votre fichier de sortie.

De cette façon, vous pouvez capturer les sorties des processus enfants.

Et un autre processus consiste à mettre directement l' >opérateur dans la commande uniquement. Donc, si nous mettons tout dans un fichier pendant que nous exécutons la commande, vous n'aurez rien à copier.

Dans ce cas, il n'est pas nécessaire d'utiliser des tuyaux. Vous pouvez utiliser simplement system, et il exécutera la commande et mettra la sortie dans ce fichier.

int my_func(){
    char *command = (char *)"/usr/bin/my_script my_arg > /tmp/my_putput_file";
    system(command);
    printf("everything saved in my_output_file");
    return 0;
}

Vous pouvez lire le tutoriel YoLinux: Fork, Exec et Process control pour plus d'informations.

Agarwal Muskan
la source
1

Notez que vous pouvez obtenir une sortie en redirigeant la sortie vers le fichier, puis en la lisant

Il a été montré dans la documentation de std::system

Vous pouvez recevoir le code de sortie en appelant une WEXITSTATUSmacro.

    int status = std::system("ls -l >test.txt"); // execute the UNIX command "ls -l >test.txt"
    std::cout << std::ifstream("test.txt").rdbuf();
    std::cout << "Exit code: " << WEXITSTATUS(status) << std::endl;
Pikacz
la source