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

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

교체 popen와 pclose함께 _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_t및 CreateProcessW불필요한 제한 등을.
— 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.