对于Windows, popen 也可以工作,但它会打开一个控制台窗口 - 它会快速闪烁你的UI应用程序。如果你想成为一名专业人士,最好禁用这种“闪烁”(特别是如果最终用户可以取消它)。
popen
所以这是我自己的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
同时获取stdout和stderr(以及写入stdin,这里没有显示)很容易让我感到轻松 pstreams header,它定义了类似的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'; // read child's stderr while (std::getline(proc.err(), line)) std::cout << "stderr: " << line << '\n'; }
假设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
#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; }
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 (fgets(buffer, sizeof buffer, pipe) != NULL) { result += buffer; } } catch (...) { pclose(pipe); throw; } pclose(pipe); return result; }
更换 popen 和 pclose 同 _popen 和 _pclose 对于Windows。
pclose
_popen
_pclose
两种可能的方法:
我不认为 popen() 是C ++标准的一部分(它是来自内存的POSIX的一部分),但它可以在我使用的每个UNIX上使用(并且你似乎是针对UNIX,因为你的命令是 ./some_command )。
popen()
./some_command
关于没有机会的可能性 popen() , 您可以使用 system("./some_command >/tmp/some_command.out"); ,然后使用普通的I / O函数来处理输出文件。
system("./some_command >/tmp/some_command.out");
我无法弄清楚为什么Codeblocks / MinGW中缺少popen / pclose。所以我通过使用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; }
以下可能是便携式解决方案。它遵循标准。
#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; }