Как выполнить команду и получить вывод команды в C ++ с помощью POSIX?

Я ищу способ получить вывод команды, когда она запускается из C ++-программы. Я посмотрел на использование функции system (), но это просто выполнит команду. Вот пример того, что я ищу:

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

Мне нужно запустить произвольную команду и получить ее вывод. Я посмотрел на Boost.org, но я не нашел ничего, что даст мне то, что мне нужно.

 #include  #include  #include  #include  #include  #include  std::string exec(const char* cmd) { std::array buffer; std::string result; std::shared_ptr pipe(popen(cmd, "r"), pclose); if (!pipe) throw std::runtime_error("popen() failed!"); while (!feof(pipe.get())) { if (fgets(buffer.data(), 128, pipe.get()) != nullptr) result += buffer.data(); } return result; } 

Версия для Pre-C ++ 11:

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

Замените popen и pclose на _popen и _pclose для Windows.

Получение как stdout, так и stderr (а также запись на stdin, не показано здесь) легко peasy с моим заголовком pstreams , который определяет classы iostream, которые работают как popen :

 #include  #include  #include  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 или, возможно, Windows с уровнем совместимости POSIX …)

 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 , но он открывает консольное окно, которое быстро мигает над вашим пользовательским интерфейсом. Если вы хотите быть профессионалом, лучше отключить этот «мигающий» (особенно если конечный пользователь может его отменить).

Итак, вот моя собственная версия для 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 

Вы можете использовать библиотеку Boost.Process . Тем не менее, это не официальная часть повышения. Я видел, как он хорошо работает для других. К сожалению, прогресс boost.process, по-видимому, застопорился. pstreams – другой (по-видимому активный) проект. Конечно, стоит попробовать, я бы сказал – но это только для совместимых с posix операционных систем.

Два возможных подхода.

1 / Я не думаю, что popen() является частью стандарта C ++ (это часть POSIX из памяти), но он доступен для всех UNIX, с которыми я работал (и вы, похоже, нацеливаете UNIX, так как ваша команда « ./some_command “).

2 / В случае system( "./some_command >/tmp/some_command.out" ) ; отсутствия popen() вы можете использовать system( "./some_command >/tmp/some_command.out" ) ; затем используйте обычные функции ввода-вывода для обработки выходного файла.

Это может быть переносное решение. Соответствует стандартам.

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

Я не мог понять, почему popen / pclose отсутствует в Codeblocks / MinGW. Поэтому я работал над проблемой, используя вместо этого CreateProcess () и CreatePipe (). Вот решение, которое сработало для меня:

 //C++11 #include  #include  #include  #include  #include  #include  #include  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; } 
  • C # - WCF - межпроцессное взаимодействие
  • Остановите запущенный процесс запуска на OS X Leopard
  • Выполнение приложения Java в отдельном процессе
  • Как скрыть окно cmd во время запуска пакетного файла?
  • Как получить STDOUT из QProcess?
  • Linux: Есть ли что-то похожее на «верх» для ввода-вывода?
  • запустить exe / process с stdin stdout и stderr?
  • Как проверить, существует ли идентификатор процесса (PID)
  • Как узнать, какие процессы обращаются к жесткому диску в системе на основе GNU / Linux?
  • Delphi - получить, какие файлы открываются приложением
  • Как проверить, существует ли процесс с данным pid в Python?
  • Interesting Posts

    Как представить шестнадцатеричное значение, такое как FFFFFFBB в программировании встроенной сборки x86?

    Игнорировать все предупреждения в определенном файле, используя LLVM / Clang

    Невозможно отформатировать Micro SDcard

    Столбец как первичный ключ или два внешних ключа в качестве первичного ключа

    Есть ли способ автоматизировать установку Android-sdk?

    Windows 8 Hyper-V – как предоставить доступ в Интернет через Интернет?

    Война с весенними ботинками без встроенного tomcat

    Используется несколько интернет-подключений.

    node-websocket-server: возможно иметь несколько отдельных «трансляций» для одного процесса node.js?

    Linux-маршрутизация и HMA

    Java 8: Обязательная проверка обработки исключений в lambda-выражениях. Почему обязательный, а не факультативный?

    Почему pydot не может найти исполняемые файлы GraphViz в Windows 8?

    Как отключить сущность из контекста в Entity Framework?

    Настройка подсетей quandry

    Какие арифметические операции одинаковы для чисел без знака и двух дополнений?

    Давайте будем гением компьютера.