我正在寻找一种方法来获得命令的输出,当它从c++程序中运行时。我已经看到了使用system()函数,但它只会执行一个命令。以下是我正在寻找的一个例子:
std::string result = system("./some_command");
我需要运行任意命令并获得其输出。我在boost.org上找过了,但是我还没有找到任何能满足我需要的东西。
我正在寻找一种方法来获得命令的输出,当它从c++程序中运行时。我已经看到了使用system()函数,但它只会执行一个命令。以下是我正在寻找的一个例子:
std::string result = system("./some_command");
我需要运行任意命令并获得其输出。我在boost.org上找过了,但是我还没有找到任何能满足我需要的东西。
当前回答
两种可能的方法:
我不认为popen()是c++标准的一部分(从内存来看,它是POSIX的一部分),但它在我使用过的每个UNIX上都可用(您似乎针对的是UNIX,因为您的命令是./some_command)。 在不存在popen()的情况下,您可以使用system("。/some_command >/tmp/some_command.out");,然后使用正常的I/O函数处理输出文件。
其他回答
#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;
}
对于Windows,用_popen和_pclose替换popen和pclose。
两种可能的方法:
我不认为popen()是c++标准的一部分(从内存来看,它是POSIX的一部分),但它在我使用过的每个UNIX上都可用(您似乎针对的是UNIX,因为您的命令是./some_command)。 在不存在popen()的情况下,您可以使用system("。/some_command >/tmp/some_command.out");,然后使用正常的I/O函数处理输出文件。
您可以在使用管道运行脚本后获得输出。当我们需要子进程的输出时,我们使用管道。
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;
}
你可以阅读YoLinux教程:Fork, Exec和进程控制了解更多信息。
我会使用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);
}
获得stdout和stderr(也写入stdin,这里没有显示)与我的pstreams头很容易,它定义了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';
// 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';
}