मैं एक कमांड को कैसे निष्पादित करूं और POSIX का उपयोग करके C ++ के भीतर कमांड का आउटपुट प्राप्त करूं?


463

जब मैं C ++ प्रोग्राम के भीतर से चलाया जाता है, तो मैं कमांड के आउटपुट प्राप्त करने का एक तरीका ढूंढ रहा हूं। मैंने system()फ़ंक्शन का उपयोग करते हुए देखा है , लेकिन यह सिर्फ एक कमांड निष्पादित करेगा। यहाँ एक उदाहरण है जो मैं देख रहा हूँ:

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

मुझे एक मनमाना कमांड चलाने और उसका आउटपुट प्राप्त करने की आवश्यकता है। मैंने boost.org को देखा है , लेकिन मुझे ऐसा कुछ नहीं मिला है जो मुझे वह देगा जो मुझे चाहिए।


इस प्रश्न के उत्तर भी देखें: /programming/52164723/how-to-execute-a-command-and-get-return-code-stdout-and-stderr-of-command-in-cनीचे दिए गए महान उत्तर के विस्तार के लिए जो पाने के तरीके प्रदान करता है return codeऔर stderrसाथ ही साथ stdoutयह उत्तर पहले से ही समझाता है
code_fodder

जवाबों:


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

पूर्व-सी ++ 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;
}

बदलें popenऔर pcloseसाथ _popenऔर _pcloseविंडोज के लिए।


69
ध्यान रखें कि यह केवल हड़पने करेंगे stdout और नहीं stderr
23

14
यह भी ध्यान रखें कि एक अपवाद हो सकता है result += buffer, इसलिए पाइप ठीक से बंद नहीं हो सकता है।
फ्रेड फू

6
@Yasky: जब प्रोग्राम को निष्पादित किया जा रहा है int main(){ puts("ERROR"); }
ड्रीमलैक्स

8
उत्तर अच्छा है, लेकिन बेहतर होगा कि आप 'चार * cmd' को 'const char * cmd' से
बदलें

29
unique_ptr यहां एक बेहतर फिट है, जहां वास्तविक संदर्भ गणना का उपयोग कभी नहीं किया जाता है।
Czipperz

77

दोनों stdout और stderr (और यह भी stdin के लिए लिख रहा है, यहाँ नहीं दिखाया गया है) प्राप्त करना मेरे pstreams हैडर के साथ आसान है , जो iostream वर्गों को परिभाषित करता है जो इस तरह काम करते हैं 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';
} 

18
मैं असहमत हूं। popenआपको C stdio API का उपयोग करने की आवश्यकता है, मुझे iostreams API पसंद है। popenआपको मैन्युअल रूप से FILEहैंडल को साफ करने की आवश्यकता होती है , जो स्वचालित रूप से pstreams करते हैं। popenकेवल const char*तर्क के लिए स्वीकार करता है , जिसे शेल इंजेक्शन के हमलों से बचने के लिए देखभाल की आवश्यकता होती है, pstreams आपको स्ट्रिंग्स के एक वेक्टर को पास करने की अनुमति देता है execv, जो अधिक सुरक्षित है। popenआपको एक पाइप के अलावा कुछ भी नहीं देता है, pstreams आपको बच्चे के PID को यह बताने के लिए अनुमति देता है कि आप इसे भेजने के लिए सिग्नल दे सकते हैं यदि यह अवरुद्ध है या बाहर नहीं निकल रहा है। उन सभी के फायदे हैं, भले ही आप केवल यूनिडायरेक्शनल आईओ चाहते हों।
जोनाथन वेकली

1
इस समाधान के साथ एक और मुद्दा यह है कि यदि बच्चा स्टैडर के लिए लिखना शुरू करने से पहले बफ़र्स को भरने और ब्लॉक करने के लिए पर्याप्त लिखने के लिए लिखता है। अभिभावक स्टडआउट पढ़ना बंद कर देंगे, जबकि बच्चा स्टडर के पढ़ने के इंतजार में अवरुद्ध है। संसाधन गतिरोध! कम से कम उन छोरों में से एक अतुल्यकालिक (यानी, थ्रेडेड) के रूप में बेहतर होगा।
जेसी चिशोल्म

1
@JesseChisholm, हाँ, यह एक समस्या हो सकती है। लेकिन आपको थ्रेड्स का उपयोग करने की आवश्यकता नहीं है क्योंकि istream इंटरफ़ेस का उपयोग करके pstreams नॉन-ब्लॉकिंग I / O के एक अनुमान को अनुमति देता है, विशेष रूप से रीडसम फ़ंक्शन का उपयोग करके , जो तत्परता का उपयोग करके जांच करता है pstreambuf::in_avail(), इसलिए ब्लॉक नहीं होगा। यह प्रक्रिया के स्टडआउट और स्टडर पर डेमोइलिप्लेक्सिंग की अनुमति देता है क्योंकि प्रत्येक में डेटा उपलब्ध है। pstreambuf::in_avail()यदि ओएस गैर-मानक फिओनैड आईओसीटीएल का समर्थन करता है, तो केवल 100% मज़बूती से काम करता है, लेकिन यह (कम से कम) जीएनयू / लिनक्स और सोलारिस पर समर्थित है।
जोनाथन वेकली

13
@chiliNUT नया 1.0.1 रिलीज़ बूस्ट लाइसेंस का उपयोग करता है।
जोनाथन वेकली

1
@JonathanWakely 5 सेकंड के टाइमआउट के बाद मैं कैसे IPstream को मार सकता हूं?
एके

34

मैं पोपेन () (++ वकास) का उपयोग करूंगा ।

लेकिन कभी-कभी आपको पढ़ने और लिखने की आवश्यकता होती है ...

ऐसा लगता है कि कोई भी चीजों को किसी भी तरह से कठिन नहीं करता है।

(एक यूनिक्स / लिनक्स / मैक पर्यावरण, या शायद विंडोज एक पॉसिक्स संगतता परत के साथ ...)

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

आप चुनिंदा () और नॉन-ब्लॉकिंग रीड्स के साथ भी खेलना चाह सकते हैं।

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
कठिन तरीका सही है :) मुझे चयन () कॉल के साथ विचार पसंद है, हालांकि इस मामले में, मुझे वास्तव में कार्य पूरा होने तक इंतजार करने की आवश्यकता है। मैं इस कोड को एक और परियोजना के लिए रखूँगा जो मेरे पास है :)
मीशा एम

4
... या आप मौजूदा पॉज़िक्स_स्पॉन फ़ंक्शन का उपयोग कर सकते हैं
प्रति जोहानसन

5
आपके execlpकॉल में एक बग है: अंतिम argपॉइंटर पारित किया जाना चाहिए (char *) NULLताकि वेरिएडिक तर्क सूची ( execlp(3)संदर्भ के लिए देखें ) को ठीक से समाप्त किया जा सके ।
क्रिस्टोफ मार्सी

क्या यह यूनिक्स, लिनक्स और खिड़कियों पर काम करेगा? क्या आप हेडर फ़ाइलों को भी कृपया कर सकते हैं?
किट्टू

आप कोड में .bat फ़ाइल कहाँ से पास कर रहे हैं?
किट्टू

33

विंडोज के लिए, popenयह भी काम करता है, लेकिन यह एक कंसोल विंडो खोलता है - जो आपके UI एप्लिकेशन पर जल्दी से फ्लैश करता है। यदि आप एक पेशेवर बनना चाहते हैं, तो इस "चमकती" को निष्क्रिय करना बेहतर है (विशेषकर यदि अंत-उपयोगकर्ता इसे रद्द कर सकता है)।

तो यहाँ विंडोज के लिए मेरा अपना संस्करण है:

(यह कोड आंशिक रूप से द कोड प्रोजेक्ट और 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

1
यह विंडोज के लिए मेरा पसंदीदा समाधान है, मुझे आशा है कि आप मेरे बदलावों को माफ कर देंगे। मैं कास्ट-कास्ट को और अधिक स्पष्ट करने का सुझाव दूंगा, जबकि मैं एक अनावश्यक प्रतिबंध के रूप में wchar_tऔर इसके स्पष्ट उपयोग पर विचार करता हूं CreateProcessW
वुल्फ

क्या आपको इस कलाकारों के साथ कोई समस्या या संभावित समस्या दिखाई देती है? मैं कम से कम कोड रखना पसंद करता हूं और आवश्यकता के बिना इसे नहीं लिखता।
TarmoPikaro

4
CreateProcess फ़ंक्शन (विंडोज़) को पढ़ने के बाद , मुझे ऐसा करने में एक वास्तविक खतरा दिखाई देता है: 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.इसलिए कॉल करने वाले को उसके मूल इनपुट को बदलने से रोकने के लिए कमांड लाइन को पहले एक अलग बफर में कॉपी करना बेहतर होगा।
वुल्फ

यह उत्तर स्टडर को ठीक से नहीं संभालता है।
Refael Sheinker

क्या यह यूनिक्स सिस्टम के लिए भी काम करता है? या मुझे यूनिक्स डिवाइस के लिए कुछ और उपयोग करना होगा?
255.tar.xz

17

दो संभावित दृष्टिकोण:

  1. मुझे नहीं लगता कि popen()यह C ++ मानक का हिस्सा है (यह मेमोरी से POSIX का हिस्सा है), लेकिन यह मेरे द्वारा काम किए गए प्रत्येक UNIX पर उपलब्ध है (और आप कमांड के बाद से UNIX को लक्षित करते प्रतीत होते हैं ./some_command)।

  2. ऑफ-मौका पर कि कोई नहीं है popen(), आप उपयोग कर सकते हैं system("./some_command >/tmp/some_command.out");, फिर आउटपुट फ़ाइल को संसाधित करने के लिए सामान्य I / O फ़ंक्शन का उपयोग करें।


पोपेन के लिए धन्यवाद, मैं अभी के लिए इसका उपयोग करने जा रहा हूं और अगर यह सामने आता है तो मैं गैर-पॉसिक्स सिस्टम के बारे में चिंता करूंगा।
मीशा एम

8

मैं यह पता नहीं लगा सका कि कोड / ब्लॉक से पोपेन / पॉक्सोस क्यों गायब है / / मिगवॉ । इसलिए मैंने इसके बजाय CreateProcess () और CreatePipe () का उपयोग करके समस्या के आसपास काम किया।

यहाँ समाधान है कि मेरे लिए काम किया है:

//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
धन्यवाद! यह इंटरनेट पर विंडोज के लिए सबसे अच्छा पॉपेन कार्यान्वयन है! और CREATE_NO_WINDOW ध्वज को पास करके अंत में कष्टप्रद cmd संकेतों से छुटकारा पा सकता है जो दिखाते हैं।
लाको टोमोव

1
आप बात कहाँ से पास करते हैं CREATE_NO_WINDOW?
Refael Sheinker

2
@ बिल मूर, यदि आप ध्यान दें, तो आपके उत्तर में एक बग है। ListStdErrकभी इस्तेमाल नहीं किया जाता है।
Refael Sheinker

7

निम्नलिखित एक पोर्टेबल समाधान हो सकता है। यह मानकों का पालन करता है।

#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
मुझे यह चेतावनी gcc के साथ मिलती है: "चेतावनी: tmpnamखतरनाक है, बेहतर उपयोग mkstemp"
मार्क Lakata

4

POSIX की मानें तो स्टडआउट पर कब्जा करने के लिए सरल कोड:

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

अधिक कार्यक्षमता के लिए कोड योगदान का स्वागत है:

https://github.com/ericcurtin/execxx


2

आप एक पाइप का उपयोग करके स्क्रिप्ट चलाने के बाद आउटपुट प्राप्त कर सकते हैं। जब हम बच्चे की प्रक्रिया का आउटपुट चाहते हैं तो हम पाइप का उपयोग करते हैं।

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

तो यहाँ स्क्रिप्ट है, जिसे आप चलाना चाहते हैं। इसे एक कमांड वैरिएबल में रखें जिसमें आपकी स्क्रिप्ट लेती है (अगर कोई तर्क नहीं है)। और वह फ़ाइल जहाँ आप स्क्रिप्ट के आउटपुट को कैप्चर करना चाहते हैं, उसे copy_fp में डालें।

तो पोपेन आपकी स्क्रिप्ट चलाता है और आउटपुट को fpipe में डालता है और फिर आप बस उसी से सब कुछ कॉपी कर सकते हैं अपनी आउटपुट फ़ाइल में।

इस तरह आप बच्चे की प्रक्रियाओं के आउटपुट पर कब्जा कर सकते हैं।

और एक और प्रक्रिया है जिसे आप सीधे डाल सकते हैं > ऑपरेटर कमांड में । इसलिए यदि हम कमांड चलाते समय सब कुछ एक फाइल में डाल देंगे, तो आपको कुछ भी कॉपी नहीं करना पड़ेगा।

उस स्थिति में, पाइप का उपयोग करने की कोई आवश्यकता नहीं है। आप बस उपयोग कर सकते हैं system, और यह कमांड चलाएगा और आउटपुट को उस फ़ाइल में डाल देगा।

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

आप अधिक जानकारी के लिए YoLinux Tutorial: Fork, Exec और Process control पढ़ सकते हैं ।


1

ध्यान दें कि आप आउटपुट को फ़ाइल पर रीडायरेक्ट करके आउटपुट प्राप्त कर सकते हैं और फिर उसे पढ़ सकते हैं

के प्रलेखन में इसे दिखाया गया था std::system

आप WEXITSTATUSमैक्रो कॉल करके निकास कोड प्राप्त कर सकते हैं ।

    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;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.