POSIX kullanarak bir komutu nasıl çalıştırabilirim ve komutun çıktısını C ++ içinde alabilirim?


463

Bir C ++ programı içinden çalıştırıldığında bir komutun çıktısını almak için bir yol arıyorum. Ben system()fonksiyonu kullanarak baktım , ama bu sadece bir komut yürütecek. İşte aradığımın bir örneği:

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

Rasgele bir komut çalıştırmak ve çıktısını almak gerekiyor. Boost.org'a baktım , ama bana ihtiyacım olanı verecek hiçbir şey bulamadım.


Ayrıca bu soruya verilen yanıtlara bakın: /programming/52164723/how-to-execute-a-command-and-get-return-code-stdout-and-stderr-of-command-in-caşağıdaki harika cevabın bir uzantısı için return codeve bu cevabın zaten stderraçıklandığı gibi stdoutve bu cevabı zaten açıklıyor
code_fodder

Yanıtlar:


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

C ++ 11 öncesi sürüm:

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

Değiştir popenve pclosebirlikte _popenve _pcloseWindows için.


70
Bu sadece çekecek unutmayın stdout'u değil stderr .
kalaxy

14
Ayrıca bir istisna oluşabileceğine dikkat edin result += buffer, bu nedenle boru düzgün kapatılmayabilir.
Fred Foo

6
@Yasky: Yürütülen program ne zaman int main(){ puts("ERROR"); }.
dreamlax

8
Cevap iyi ama 'char * cmd' yerine 'const char * cmd'
fnc12

29
unique_ptr, burada gerçek referans sayısının asla kullanılmadığı daha iyi bir seçimdir.
Czipperz

77

Hem stdout hem de stderr'i almak (ve ayrıca burada gösterilmeyen stdin'e yazmak ), benim gibi çalışan iostream sınıflarını tanımlayan pstreams başlığımla kolayca bezelyepopen :

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

18
Katılmıyorum. popenC stdio API kullanmanızı gerektirir, ben iostreams API tercih ederim. sapı popenmanuel olarak temizlemenizi gerektirir FILE, pstreams bunu otomatik olarak yapar. popensadece const char*kabuk enjeksiyon saldırılarından kaçınmak için özen gerektiren bir argüman için kabul eder , pstreams benzer dizeleri vektöründen geçirmenize izin verir execv, bu da daha güvenlidir. popensize pipodan başka bir şey vermez, pstreams size çocuğun PID'sini söyler, örneğin engellenirse veya çıkmazsa onu öldürmek için sinyal göndermenize izin verir. Tüm bunlar sadece tek yönlü G / Ç isteseniz bile avantajlıdır.
Jonathan Wakely

1
Bu çözümle ilgili başka bir sorun, çocuğun stdout'a yazmaya başlamadan önce tamponları doldurmak ve engellemek için yeterince stderr'e yazmasıdır. Ebeveyn okuma stdout'unu engeller, ancak çocuk stderr'ın okunmasını beklerken engellenir. kaynak kilitlenmesi! Bu döngülerden en az biri asenkron (yani dişli) kadar iyi olacaktır.
Jesse Chisholm

1
@ JesseChisholm, evet, bu bir sorun olabilir. Ancak iş parçacıkları kullanmanıza gerek yoktur, çünkü pstreams, iostream arabirimini kullanarak, özellikle de hazır olup olmadığını kontrol eden readsome işlevini kullanarak, engellemeyen G / Ç yaklaşımına izin verir pstreambuf::in_avail(), bu nedenle engellemez. Bu, her biri mevcut verilere sahip olduğundan, işlemin stdout ve stderr'inin çoğullamasına neden olur. pstreambuf::in_avail()yalnızca işletim sistemi standart olmayan FIONREAD ioctl'i destekliyorsa, ancak (en azından) GNU / Linux ve Solaris'te destekleniyorsa% 100 güvenilir bir şekilde çalışır.
Jonathan Wakely

13
@chiliNUT yeni 1.0.1 sürümü Boost lisansını kullanır.
Jonathan Wakely

1
@JonathanWakely 5 saniyelik bir zaman aşımı söyledikten sonra ipstream'i nasıl öldürebilirim?
AK

34

Bana kalırsa doğru popen () (++ waqas) .

Ama bazen okumaya ve yazmaya ihtiyacınız olur ...

Görünüşe göre artık kimse işleri zor yoldan yapmıyor.

(Unix / Linux / Mac ortamı veya POSIX uyumluluk katmanına sahip Windows varsayalım ...)

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())*/
}

Ayrıca select () ve engellemeyen okumalarla oynamak isteyebilirsiniz.

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

1
Zor yol doğru :) Ben select () çağrı ile fikir gibi, bu durumda, aslında görev tamamlanana kadar beklemek gerekir. Sahip olduğum başka bir proje için bu kodu saklayacağım :)
Misha M

4
... ya da mevcut posix_spawnp işlevini kullanabilirsiniz
Per Johansson

5
Kişisel execlpçağrı bir hata var: Geçen arggeçti gösterici olmalıdır (char *) NULLdüzgün (bkz variadic argüman listesi sonlandırmak için execlp(3)referans için).
Kristóf Marussy

Bu unix, linux ve windows üzerinde çalışır mı? Lütfen başlık dosyalarını da kullanabilir misiniz?
kittu

Koddaki .bat dosyasını nerede geçiriyorsunuz?
kittu

33

Windows için popende çalışır, ancak UI uygulamanızın üzerinde hızla yanıp sönen bir konsol penceresi açılır. Profesyonel olmak istiyorsanız, bu "yanıp sönmeyi" devre dışı bırakmak daha iyidir (özellikle son kullanıcı iptal edebilirse).

İşte Windows için kendi sürümüm:

(Bu kod, Kod Projesi ve MSDN örneklerinde yazılmış fikirlerden kısmen yeniden birleştirilmiştir .)

#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

1
Bu benim Windows için en sevdiğim çözüm, umarım değişikliklerimi affedersiniz. Ben açık kullanımını dikkate oysa const-cast daha açık hale getirmek için öneririm wchar_tve CreateProcessWgereksiz bir kısıtlama olarak.
Kurt

Bu oyuncu kadrosunda herhangi bir sorun veya potansiyel bir sorun görüyor musunuz? Kodu minimumda tutmayı tercih ediyorum ve gerek kalmadan yazmam.
TarmoPikaro

4
CreateProcess işlevini (Windows) okuduktan sonra , bunu yaparken gerçek bir tehlike görüyorum: 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.Bu nedenle, arayanın orijinal girdisini değiştirmesini önlemek için önce komut satırını ayrı bir arabelleğe kopyalamak daha iyi olabilir.
Kurt

Bu cevap stderr'ı düzgün işlemez.
Refael Sheinker

Bu aynı zamanda Unix sistemleri için de geçerli mi? Yoksa bir Unix cihazı için başka bir şey mi kullanmam gerekir?
255.tar.xz

17

İki olası yaklaşım:

  1. popen()C ++ standardının (bellekten POSIX'in bir parçası) bir parçası olduğunu düşünmüyorum , ancak birlikte çalıştığım her UNIX'te mevcut (ve komutunuz olduğu için UNIX'i hedefliyor gibi görünüyorsunuz ./some_command).

  2. Hayır olmaması durumunda popen(), system("./some_command >/tmp/some_command.out");çıktı dosyasını işlemek için normal G / Ç işlevlerini kullanabilirsiniz.


Popen için teşekkürler, şimdilik kullanacağım ve POSIX olmayan sistemler hakkında endişeleneceğim.
Misha M

8

Aşağıdakiler taşınabilir bir çözüm olabilir. Standartlara uygundur.

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

4
Bu uyarıyı gcc ile alıyorum: "uyarı: kullanımı tmpnamtehlikeli, daha iyi kullanım mkstemp"
Mark Lakata

8

Kod :: Blocks / MinGW neden popen / pclose eksik olduğunu anlayamadım . Bu yüzden bunun yerine CreateProcess () ve CreatePipe () kullanarak sorunu giderdim.

İşte benim için işe yarayan çözüm:

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

5
Teşekkür ederim! Bu internette Windows için en iyi popen uygulamasıdır! Ve CREATE_NO_WINDOW bayrağını geçerek nihayet ortaya çıkan can sıkıcı cmd istemlerinden kurtulabilirsiniz.
Lacho Tomov

1
Nereden CREATE_NO_WINDOWgeçiyorsun?
Refael Sheinker

2
@ Bill Moore, fark ederseniz, cevabınızda bir hata var. ListStdErrasla kullanılmaz.
Refael Sheinker

4

POSIX varsayarsak, stdout'u yakalamak için basit kod:

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

Kod katkıları daha fazla işlevsellik için kabul edilir:

https://github.com/ericcurtin/execxx


2

Pipo kullanarak bir komut dosyası çalıştırdıktan sonra çıktıyı alabilirsiniz. Çocuk sürecinin çıktısını istediğimizde boruları kullanıyoruz.

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

İşte size çalıştırmak istediğiniz komut dosyası. Komut dosyanızın aldığı bağımsız değişkenleri içeren bir komut değişkenine koyun (bağımsız değişken yoksa hiçbir şey). Ve komut dosyasının çıktısını yakalamak istediğiniz dosyayı copy_fp dosyasına koyun.

Böylece popen betiğinizi çalıştırır ve çıktıyı fpipe'a koyar ve bundan sonra her şeyi çıktı dosyanıza kopyalayabilirsiniz.

Bu şekilde alt süreçlerin çıktılarını yakalayabilirsiniz.

Ve başka bir işlem, >operatörü doğrudan komuta koyabileceğinizdir . Bu yüzden, komutu çalıştırırken her şeyi bir dosyaya koyarsak, hiçbir şeyi kopyalamanız gerekmez.

Bu durumda, boru kullanmaya gerek yoktur. Sadece kullanabilirsiniz systemve komutu çalıştıracak ve çıktıyı bu dosyaya koyacaktır.

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

Daha fazla bilgi için YoLinux Eğitimi: Çatal, Yürütme ve Proses kontrolü bölümünü okuyabilirsiniz .


1

Çıktıyı dosyaya yönlendirerek ve ardından okuyarak çıktı alabileceğinizi unutmayın.

Dokümantasyonunda gösterilmiştir. std::system

WEXITSTATUSMakro çağırarak çıkış kodunu alabilirsiniz .

    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;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.