如何使用POSIX执行一个命令并在C ++中获取命令的输出?

我正在寻找一种方法来获取从C ++程序运行时的命令的输出。 我已经看过使用system()函数,但这只是执行一个命令。 这里是我正在寻找的一个例子:

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

我需要运行一个任意的命令,并得到它的输出。 我看过Boost.org,但是我还没有find任何能够给我所需要的东西。

 #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::shared_ptr<FILE> pipe(popen(cmd, "r"), pclose); if (!pipe) throw std::runtime_error("popen() failed!"); while (!feof(pipe.get())) { if (fgets(buffer.data(), 128, pipe.get()) != std::nullptr) result += buffer.data(); } return result; } 

Pre-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 (!feof(pipe)) { if (fgets(buffer, 128, pipe) != NULL) result += buffer; } } catch (...) { pclose(pipe); throw; } pclose(pipe); return result; } 

用Windows的_popen_pclosereplacepopenpclose

同时获取stdout和stderr(也写入stdin,这里没有显示)很容易与我的pstreams头,它定义了像popen一样工作的iostream类:

 #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'; // read child's stderr while (std::getline(proc.err(), line)) std::cout << "stderr: " << line << '\n'; } 

我会用popen() (++ waqas)

但有时你需要读写

似乎没有人再努力地做事情了。

(假设一个Unix / Linux / 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()和非阻塞读取。

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

对于Windows, popen也可以工作,但是它打开了控制台窗口 – 在UI应用程序中快速闪烁。 如果你想成为一名专业人士,最好禁用这个“闪烁”(特别是如果最终用户可以取消它)。

所以这里是我自己的Windows版本:

(这个代码部分地从代码项目和MSDN样本中编写的想法重组)

 // // 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; STARTUPINFO si = { sizeof(STARTUPINFO) }; 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 (50ms), 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 /我不认为popen()是C ++标准的一部分(它是内存中的POSIX的一部分),但是它在每一个与我一起工作的UNIX上都可用(而且由于你的命令是“ ./some_command “)。

2 /关于没有popen()的机会,你可以使用system( "./some_command >/tmp/some_command.out" ) ; 然后使用正常的I / Ofunction来处理输出文件。

您可以使用库Boost.Process 。 虽然这不是官方的一部分。 我已经看到它很好地为其他人工作。 不幸的是,boost.process进度显然已经停滞。 pstreams是另一个(显然是活跃的)项目。 当然值得一试我会说 – 但它只适用于POSIX兼容的操作系统。

这可能是一个便携式解决scheme。 遵循标准。

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

我不知道为什么poblock / pclose从Codeblocks / MinGW丢失。 所以我通过使用CreateProcess()和CreatePipe()来解决这个问题。 这是为我工作的解决scheme:

 //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:%dn:%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:%dn:%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; }