Bagaimana cara menjalankan perintah dan mendapatkan output dari perintah dalam C ++ menggunakan POSIX?

463

Saya mencari cara untuk mendapatkan output dari sebuah perintah ketika dijalankan dari dalam program C ++. Saya telah melihat menggunakan system()fungsi, tetapi itu hanya akan menjalankan perintah. Berikut ini contoh yang saya cari:

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

Saya perlu menjalankan perintah arbitrer dan mendapatkan hasilnya. Saya telah melihat boost.org , tetapi saya belum menemukan apa pun yang akan memberikan apa yang saya butuhkan.

Misha M
sumber
Lihat juga jawaban dalam pertanyaan ini: /programming/52164723/how-to-execute-a-command-and-get-return-code-stdout-and-stderr-of-command-in-cuntuk perpanjangan dari jawaban hebat di bawah ini yang menyediakan metode untuk mendapatkan return codedan stderrjuga stdoutjawaban ini sudah menjelaskan
code_fodder
2
@code_fodder Anda dapat membuat tautan ke stackoverflow.com/questions/52164723/...
Jonas Stein

Jawaban:

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

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

Ganti popendan pclosedengan _popendan _pcloseuntuk Windows.

waqas
sumber
69
Ketahuilah bahwa ini hanya akan mengambil stdout dan bukan stderr .
kalaxy
14
Perlu diketahui juga bahwa pengecualian dapat terjadi result += buffer, sehingga pipa mungkin tidak ditutup dengan benar.
Fred Foo
6
@Yasky: Saat program sedang dijalankan int main(){ puts("ERROR"); }.
dreamlax
8
Jawabannya bagus tetapi akan lebih baik jika Anda mengganti 'char * cmd' dengan 'const char * cmd'
fnc12
29
unique_ptr lebih cocok di sini, di mana jumlah referensi yang sebenarnya tidak pernah digunakan.
Czipperz
77

Mendapatkan stdout dan stderr (dan juga menulis ke stdin, tidak ditampilkan di sini) mudah dikenali dengan header pstreams saya , yang mendefinisikan kelas iostream yang berfungsi seperti 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
sumber
18
Saya tidak setuju. popenmengharuskan Anda untuk menggunakan C stdio API, saya lebih suka API iostreams. popenmengharuskan Anda membersihkan FILEpegangan secara manual , pstreams melakukannya secara otomatis. popenhanya menerima const char*argumen, yang membutuhkan kehati-hatian untuk menghindari serangan injeksi shell, pstreams memungkinkan Anda untuk mengirim vektor string yang serupa execv, yang lebih aman. popenmemberi Anda apa-apa selain pipa, pstreams memberi tahu Anda PID anak yang memungkinkan Anda mengirim sinyal misalnya membunuhnya jika terhalang atau tidak keluar. Semua itu adalah keuntungan bahkan jika Anda hanya menginginkan IO searah.
Jonathan Wakely
1
Masalah lain dengan solusi ini adalah jika anak menulis ke stderr cukup untuk mengisi buffer dan memblokir sebelum mulai menulis ke stdout. Orang tua akan memblokir membaca stdout, sementara anak diblokir menunggu stderr dibaca. kebuntuan sumber daya! Setidaknya satu dari loop itu akan lebih baik sebagai asinkron (yaitu, berulir).
Jesse Chisholm
1
@JesseChisholm, ya, itu bisa menjadi masalah. Tetapi Anda tidak perlu menggunakan utas karena pstreams memungkinkan perkiraan I / O non-pemblokiran menggunakan antarmuka iostream, khususnya menggunakan fungsi readsome , yang memeriksa kesiapan penggunaan pstreambuf::in_avail(), jadi tidak akan memblokir. Itu memungkinkan demultiplexing pada stdout dan stderr proses karena masing-masing memiliki data yang tersedia. pstreambuf::in_avail()hanya berfungsi 100% andal jika OS mendukung FIONREAD ioctl non-standar, tetapi itu didukung pada (setidaknya) GNU / Linux dan Solaris.
Jonathan Wakely
13
@chiliNUT rilis 1.0.1 baru menggunakan lisensi Boost.
Jonathan Wakely
1
@ JonathanWakely bagaimana saya bisa membunuh ipstream setelah mengatakan batas waktu 5 detik?
AK
34

Saya akan menggunakan popen () (++ waqas) .

Tetapi kadang-kadang Anda perlu membaca dan menulis ...

Sepertinya tidak ada yang melakukan hal-hal yang sulit lagi.

(Dengan asumsi lingkungan Unix / Linux / Mac, atau mungkin Windows dengan lapisan kompatibilitas 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())*/
}

Anda juga mungkin ingin bermain-main dengan bacaan pilih () dan non-pemblokiran.

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
sumber
1
Cara yang sulit adalah benar :) Saya suka ide dengan panggilan select (), meskipun dalam kasus ini, saya benar-benar perlu menunggu sampai tugas selesai. Saya akan menyimpan kode ini untuk proyek lain yang saya miliki :)
Misha M
4
... atau Anda dapat menggunakan fungsi posix_spawnp yang ada
Per Johansson
5
execlpPanggilan Anda memiliki bug: argpenunjuk terakhir yang dilewati harus (char *) NULLmengakhiri daftar argumen variadik dengan benar (lihat execlp(3)untuk referensi).
Kristóf Marussy
Apakah ini akan berfungsi di unix, linux dan windows? Bisakah Anda menundukkan file juga?
kittu
Di mana Anda melewati file .bat dalam kode?
kittu
33

Untuk Windows, popenjuga berfungsi, tetapi membuka jendela konsol - yang dengan cepat membuka aplikasi UI Anda. Jika Anda ingin menjadi seorang profesional, lebih baik menonaktifkan "flashing" ini (terutama jika pengguna akhir dapat membatalkannya).

Jadi di sini adalah versi saya sendiri untuk Windows:

(Kode ini sebagian direkombinasi dari ide-ide yang ditulis dalam The Code Project dan sampel 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
sumber
1
Ini adalah solusi favorit saya untuk Windows, saya harap Anda memaafkan perubahan saya. Saya menyarankan untuk membuat const-cast lebih eksplisit, sedangkan saya menganggap penggunaan eksplisit wchar_tdan CreateProcessWsebagai batasan yang tidak perlu.
Wolf
Apakah Anda melihat masalah atau potensi masalah dengan pemeran ini? Saya lebih suka menyimpan kode minimal dan tidak menulisnya tanpa perlu.
TarmoPikaro
4
Setelah membaca fungsi CreateProcess (Windows) , saya melihat bahaya nyata dalam melakukan ini: 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.Jadi mungkin lebih baik untuk menyalin baris perintah ke buffer terpisah terlebih dahulu, untuk mencegah penelepon dari mendapatkan input aslinya diubah.
Wolf
Jawaban ini tidak menangani stderr dengan benar.
Refael Sheinker
Apakah ini juga berfungsi untuk sistem Unix? Atau haruskah saya menggunakan sesuatu yang lain untuk perangkat Unix?
255.tar.xz
17

Dua kemungkinan pendekatan:

  1. Saya tidak berpikir itu popen()adalah bagian dari standar C ++ (ini bagian dari POSIX dari memori), tetapi tersedia di setiap UNIX yang pernah saya gunakan (dan Anda sepertinya menargetkan UNIX karena perintah Anda ./some_command).

  2. Jika tidak ada popen(), Anda dapat menggunakan system("./some_command >/tmp/some_command.out");, lalu gunakan fungsi I / O normal untuk memproses file output.

paxdiablo
sumber
Terima kasih untuk popen, saya akan menggunakannya untuk saat ini dan saya akan khawatir tentang sistem non-POSIX jika itu muncul.
Misha M
8

Saya tidak tahu mengapa popen / pclose hilang dari Code :: Blocks / MinGW. Jadi saya mengatasi masalah dengan menggunakan CreateProcess () dan CreatePipe () sebagai gantinya.

Inilah solusi yang bekerja untuk saya:

//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
sumber
5
Terima kasih! Ini adalah implementasi popen terbaik untuk Windows di Internet! Dan dengan melewati flag CREATE_NO_WINDOW orang akhirnya dapat menyingkirkan cmd prompt yang muncul.
Lacho Tomov
1
Di mana Anda melewati benda itu CREATE_NO_WINDOW?
Refael Sheinker
2
@ Bill Moore, jika Anda perhatikan, ada bug dalam jawaban Anda. ListStdErrtidak pernah digunakan.
Refael Sheinker
7

Berikut ini mungkin solusi portabel. Ini mengikuti standar.

#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
sumber
4
Saya mendapatkan peringatan ini dengan gcc: "peringatan: penggunaan tmpnamberbahaya, lebih baik digunakan mkstemp"
Mark Lakata
4

Dengan asumsi POSIX, kode sederhana untuk menangkap stdout:

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

Kontribusi kode diterima untuk lebih banyak fungsi:

https://github.com/ericcurtin/execxx

ericcurtin
sumber
2

Anda bisa mendapatkan output setelah menjalankan skrip menggunakan pipa. Kami menggunakan pipa ketika kami ingin hasil dari proses anak.

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

Jadi inilah skrip yang ingin Anda jalankan. Masukkan ke dalam variabel perintah dengan argumen yang diambil skrip Anda (tidak ada jika tidak ada argumen). Dan file tempat Anda ingin mengambil output skrip, taruh di copy_fp.

Jadi popen menjalankan skrip Anda dan menempatkan output dalam fpipe dan kemudian Anda bisa menyalin semuanya dari itu ke file output Anda.

Dengan cara ini Anda dapat menangkap output dari proses anak.

Dan proses lainnya adalah Anda bisa langsung menempatkan >operator di perintah saja. Jadi jika kita akan meletakkan semuanya dalam file saat kita menjalankan perintah, Anda tidak perlu menyalin apa pun.

Dalam hal ini, tidak perlu menggunakan pipa. Anda bisa menggunakan adil system, dan itu akan menjalankan perintah dan meletakkan output di file itu.

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

Anda dapat membaca Tutorial YoLinux: Fork, Exec, dan Kontrol proses untuk informasi lebih lanjut.

Muskan Agarwal
sumber
1

Perhatikan bahwa Anda bisa mendapatkan output dengan mengarahkan output ke file dan kemudian membacanya

Itu ditunjukkan dalam dokumentasi std::system

Anda dapat menerima kode keluar dengan memanggil WEXITSTATUSmakro.

    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
sumber