我正在尋找一種從C ++程序中運行時獲取命令輸出的方法。 我已經看過使用system()
函數,但這隻會執行一個命令。 這是我要尋找的示例: ios
std::string result = system("./some_command");
我須要運行任意命令並獲取其輸出。 我查看了boost.org ,但沒有找到任何能夠知足我需求的東西。 windows
使用個人pstreams標頭輕鬆獲取stdout和stderr(以及寫入stdin,此處未顯示)很容易,它定義了像popen
同樣工做的iostream類: bash
#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'; }
如下多是可移植的解決方案。 它遵循標準。 函數
#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; }
對於Windows, popen
也可使用,但它會打開一個控制檯窗口-快速在您的UI應用程序上閃爍。 若是您想成爲專業人士,則最好禁用此「閃爍」功能(尤爲是若是最終用戶能夠取消它)。 ui
因此這是我本身的Windows版本: spa
(此代碼部分與The Code Project和MSDN示例中編寫的思想進行了從新組合。) code
#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
我沒法弄清楚爲何Code :: Blocks / MinGW中缺乏popen / pclose。 所以,我經過使用CreateProcess()和CreatePipe()來解決此問題。 orm
這是對我有用的解決方案: ip
//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; }
兩種可能的方法: 內存
我不認爲popen()
是C ++標準的一部分(它是內存中POSIX的一部分),可是它在我使用過的每一個UNIX上均可用(而且您彷佛以UNIX爲目標,由於您的命令是./some_command
) 。
若是沒有popen()
,可使用system("./some_command >/tmp/some_command.out");
,而後使用常規I / O功能處理輸出文件。