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 codestderr뿐만 아니라 stdout이 대답은 이미 설명 있음
code_fodder

2
당신이 할 수있는 링크를 만들 수 있습니다 @code_fodder stackoverflow.com/questions/52164723/...
조나스 스타 인

답변:


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

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

교체 popenpclose함께 _popen_pcloseWindows 용.


69
이것은 단지 사로 잡고 있음을 유의 표준 출력을 하지 열려진 .
kalaxy

14
에서 예외가 발생할 수 있으므로 result += buffer파이프가 제대로 닫히지 않았을 수도 있습니다.
Fred Foo

6
@Yasky : 실행중인 프로그램이입니다 int main(){ puts("ERROR"); }.
dreamlax 2014

8
대답은 좋지만 'char * cmd'를 'const char * cmd'로
바꾸면 더 좋습니다.

29
unique_ptr은 실제 참조 카운트가 사용되지 않는 여기에 더 적합합니다.
Czipperz

77

stdout과 stderr (그리고 여기에 표시되지 않은 stdin에 쓰는 것)을 얻는 것은 pstreams 헤더를 사용 하여 쉽게 수행 할 수 있습니다 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
동의하지 않습니다. popenC stdio API를 사용해야합니다 .iostreams API를 선호합니다. popen수동으로 정리 필요 FILE핸들을, pstreams은 자동으로 그렇게. 쉘 인젝션 공격을 피하기 위해주의를 기울여야하는 인수에 popen대해서만 a const char*를 허용합니다 .pstreams는와 비슷한 문자열 벡터를 전달할 수 execv있으므로 더 안전합니다. popenpstreams는 파이프를 제공합니다. pstreams는 자녀의 PID를 통해 신호를 보낼 수 있습니다. 단방향 IO 만 원하는 경우에도 이러한 모든 이점이 있습니다.
Jonathan Wakely

1
이 솔루션의 또 다른 문제는 자식이 stdout에 쓰기를 시작하기 전에 버퍼를 채우고 차단하기에 충분할 정도로 stderr에 쓰는 경우입니다. 부모는 stdout 읽기를 차단하고 자식은 stderr가 읽히기를 기다리는 동안 차단됩니다. 자원 교착 상태! 이러한 루프 중 적어도 하나는 비동기식 (즉, 스레드)보다 낫습니다.
Jesse Chisholm

1
@JesseChisholm, 그렇습니다. 문제가 될 수 있습니다. 그러나 pstreams는 iostream 인터페이스, 특히 readsome 함수를 사용하여 비 차단 I / O의 근사치를 허용하므로 스레드를 사용할 필요가 없으므로 차단 기능을 사용 pstreambuf::in_avail()하지 않습니다. 이를 통해 각각의 데이터를 사용할 수 있으므로 프로세스의 stdout 및 stderr에서 디 멀티플렉싱이 가능합니다. pstreambuf::in_avail()OS가 비표준 FIONREAD ioctl을 지원하지만 적어도 GNU / Linux 및 Solaris에서 지원되는 경우에만 100 % 안정적으로 작동합니다.
Jonathan Wakely

13
@chiliNUT 새로운 1.0.1 릴리스는 Boost 라이센스를 사용합니다.
Jonathan Wakely

1
@JonathanWakely 5 초 타임 아웃을 말한 후 ipstream을 어떻게 죽일 수 있습니까?
AK

34

내가 사용하는 거라고 는 popen () (++ waqas) .

그러나 때로는 읽기와 쓰기가 필요합니다 ...

아무도 더 이상 어려운 일을하지 않는 것 같습니다.

(유닉스 / 리눅스 / Mac 환경 또는 POSIX 호환성 레이어가있는 Windows를 가정하면 ...)

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

select () 및 non-blocking 읽기로 놀아 볼 수도 있습니다.

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
어려운 방법은 옳습니다 :) select () 호출로 아이디어를 좋아하지만이 경우 실제로 작업이 완료 될 때까지 기다려야합니다. 나는 :)이 또 다른 프로젝트에이 코드하겠습니다
미샤 M

4
... 또는 기존 posix_spawnp 함수를 사용할 수 있습니다
Per Johansson

5
귀하의 execlp전화는 버그가 : 마지막 arg통과 포인터가 있어야합니다 (char *) NULL제대로 (참조 가변 인수 목록을 종료 execlp(3)참조).
Kristóf Marussy

이것은 유닉스, 리눅스 및 윈도우에서 작동합니까? 헤더 파일도 만족시킬 수 있습니까?
kittu

코드에서 .bat 파일을 어디로 전달합니까?
kittu

33

Windows의 경우 popen에도 작동하지만 UI 응용 프로그램을 통해 빠르게 깜박이는 콘솔 창이 열립니다. 전문가가 되려면이 "깜박임"을 비활성화하는 것이 좋습니다 (특히 최종 사용자가 취소 할 수있는 경우).

그래서 여기 내 Windows 용 내 버전이 있습니다.

이 코드는 코드 프로젝트 및 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
이것은 Windows에서 가장 좋아하는 솔루션입니다. 변경 사항을 용서하시기 바랍니다. 나는의 명시적인 사용을 고려, 반면 CONST 캐스트 더 명시 적으로 만드는 게 좋을 것 wchar_tCreateProcessW불필요한 제한 등을.
Wolf

이 캐스트에 문제가 있거나 잠재적 인 문제가 있습니까? 코드를 최소한으로 유지하고 필요없이 작성하지 않는 것이 좋습니다.
TarmoPikaro

4
CreateProcess 함수 (Windows)를 읽은 후에 는이 작업을 수행하는 데 실제로 위험이 있습니다. 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.따라서 호출자가 원래 입력을 변경하지 못하도록 명령 줄을 별도의 버퍼에 먼저 복사하는 것이 좋습니다.
Wolf

이 답변은 stderr을 올바르게 처리하지 못합니다.
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 기능을 사용하여 출력 파일을 처리 할 수 ​​있습니다.


popen에 감사드립니다. 지금은 사용할 것입니다. POSIX 이외의 시스템이 걱정된다면 걱정할 것입니다.
Misha M

8

왜 popen / pclose가 Code :: Blocks / MinGW에 없는지 알 수 없었습니다 . 그래서 대신 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
감사합니다! 이것은 인터넷에서 Windows에 가장 적합한 구현입니다! 그리고 CREATE_NO_WINDOW 플래그를 전달하면 표시되는 성가신 cmd 프롬프트를 제거 할 수 있습니다.
Lacho Tomov 2018

1
CREATE_NO_WINDOW물건을 어디로 전달 합니까?
Refael Sheinker

2
@Bill Moore, 당신이 알면 대답에 버그가 있습니다. 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"
Mark Lakata

4

POSIX를 가정하고 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;
}

더 많은 기능을 위해 코드 기여를 환영합니다 :

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에 넣으십시오.

따라서 popen은 스크립트를 실행하고 출력을 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;
}

당신이 읽을 수있는 포크, Exec에서 및 프로세스 제어 : YoLinux 자습서 자세한 내용은.


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;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.