Does anyone know how to catch the output (I think its stdout) from execvp
instead of the system printing it (in c on linux) in the terminal?
有没有人知道如何捕获输出(我认为它的标准输出)来自execvp而不是系统在终端中打印它(在Linux上的c)?
5 个解决方案
#1
6
execvp
replaces the current running process in memory. There's no "catching" the output.
execvp替换内存中当前运行的进程。没有“捕捉”输出。
I suspect you're trying to run an external process from an existing process, and parse its output. For that you need to use popen()
which does a fork()
then an exec()
, returning a FILE *
to read (which will be the stdout
of the process you just ran).
我怀疑你正在尝试从现有进程运行外部进程,并解析其输出。为此你需要使用popen(),它执行fork()然后执行exec(),返回一个FILE *来读取(这将是你刚刚运行的进程的stdout)。
#2
4
I distrust popen/pclose
, as I've worked on too many systems where SIGCHLD
was handled slightly differently. And I distrust the sh
-shell parsing used by popen
, since I rarely use it.
我不信任popen / pclose,因为我曾经处理太多系统,其中SIGCHLD的处理方式略有不同。而且我不信任popen使用的sh-shell解析,因为我很少使用它。
The short 22-year-old O'Reilly book Using C on the UNIX System, by Dave Curry is still a very good reference for this sort of stuff.
简短的22岁的O'Reilly在Dave Curry上的“在UNIX系统上使用C”这本书仍然是这类内容的一个很好的参考书。
Anyway, here is some code. It is a bit lengthy, as it parses the sample string "/bin/ls /etc"
into the array {"/bin/ls", "/etc", 0}
. But I find using the string format easier and shorter 98% of the time, although this example belies that.
无论如何,这里有一些代码。它有点冗长,因为它将样本字符串“/ bin / ls / etc”解析为数组{“/ bin / ls”,“/ etc”,0}。但我发现使用字符串格式更容易,98%的时间更短,尽管这个例子掩盖了这一点。
This code generates a listing of /etc.
You'll need to change some stuff like e.g. NUMBER()
which is the same asXtNumber()
. And you'll need to decide whether it matches your handling of SIGCHLD
.
此代码生成/ etc的列表。你需要改变一些东西,例如NUMBER()与XtNumber()相同。您需要确定它是否与您对SIGCHLD的处理相匹配。
int main(void) { // list the files in /etc
char buf[100];
FILE *fp;
int pid = spawnfp("/bin/ls /etc", &fp);
while (fgets(buf, sizeof buf, fp))
printf("%s", buf);
fclose(fp); // pclose() replacement
kill(pid, SIGKILL); // pclose() replacement
return 0;
}
The subroutines here are:
这里的子程序是:
static int spawnpipe(const char *argv[], int *fd) // popen() replacement
{
int pid;
int pipe_fds[2];
if (pipe(pipe_fds) < 0)
FatalError("pipe");
switch ((pid = fork()))
{
case -1:
FatalError("fork");
case 0: // child
close(1);
close(2);
dup(pipe_fds[0]);
dup(pipe_fds[1]);
close(pipe_fds[0]);
close(pipe_fds[1]);
execv(argv[0], (char * const *)argv);
perror("execv");
_exit(EXIT_FAILURE); // sic, not exit()
default:
*fd = pipe_fds[0];
close(pipe_fds[1]);
return pid;
}
}
This converts an ascii string to an argv
list, which is probably useless to you:
这会将ascii字符串转换为argv列表,这对您来说可能没用:
Bool convertStringToArgvList(char *p, const char **argv, int maxNumArgs)
{
// Break up a string into tokens, on spaces, except that quoted bits,
// with single-quotes, are kept together, without the quotes. Such
// single-quotes cannot be escaped. A double-quote is just an ordinary char.
// This is a *very* basic parsing, but ok for pre-programmed strings.
int cnt = 0;
while (*p)
{
while (*p && *p <= ' ') // skip spaces
p++;
if (*p == '\'') // single-quote block
{
if (cnt < maxNumArgs)
argv[cnt++] = ++p; // drop quote
while (*p && *p != '\'')
p++;
}
else if (*p) // simple space-delineated token
{
if (cnt < maxNumArgs)
argv[cnt++] = p;
while (*p > ' ')
p++;
}
if (*p)
*p++ = 0; // nul-terminate
}
if (cnt < maxNumArgs)
argv[cnt++] = 0;
return cnt <= maxNumArgs; // check for too many tokens (unlikely)
}
This converts the argument string to tokens and, more importantly, the fd
to an fp
, since the OP requested stdout
:
这会将参数字符串转换为标记,更重要的是,将fd转换为fp,因为OP请求标准输出:
int spawnfp(const char *command, FILE **fpp)
{
const char *argv[100];
int fd, pid;
if (!convertStringToArgvList(strdupa(command), argv, NUMBER(argv)))
FatalError("spawnfp");
pid = spawnpipe(argv, &fd);
*fpp = fdopen(fd, "r");
return pid;
}
#4
1
As others have said, popen
is what you want to use. Something like this...
正如其他人所说,popen是你想要使用的。这样的东西......
#include <iomanip>
#include <iostream>
using namespace std;
const int MAX_BUFFER = 255;
int main()
{
string cmd;
cout << "enter cmd: ";
cin >> cmd;
cout << endl << "running " << cmd << "…" << endl;
string stdout;
char buffer[MAX_BUFFER];
FILE *stream = popen(cmd.c_str(), "r");
while ( fgets(buffer, MAX_BUFFER, stream) != NULL )
stdout.append(buffer);
pclose(stream);
cout << endl << "output: " << endl << stdout << endl;
}
#5
0
I found this answer, which gives popen
a execvp
style interface.
我找到了这个答案,它为popen提供了一个execvp风格的界面。
https://codereview.stackexchange.com/questions/31063/popen-with-array-of-arguments
#1
6
execvp
replaces the current running process in memory. There's no "catching" the output.
execvp替换内存中当前运行的进程。没有“捕捉”输出。
I suspect you're trying to run an external process from an existing process, and parse its output. For that you need to use popen()
which does a fork()
then an exec()
, returning a FILE *
to read (which will be the stdout
of the process you just ran).
我怀疑你正在尝试从现有进程运行外部进程,并解析其输出。为此你需要使用popen(),它执行fork()然后执行exec(),返回一个FILE *来读取(这将是你刚刚运行的进程的stdout)。
#2
4
I distrust popen/pclose
, as I've worked on too many systems where SIGCHLD
was handled slightly differently. And I distrust the sh
-shell parsing used by popen
, since I rarely use it.
我不信任popen / pclose,因为我曾经处理太多系统,其中SIGCHLD的处理方式略有不同。而且我不信任popen使用的sh-shell解析,因为我很少使用它。
The short 22-year-old O'Reilly book Using C on the UNIX System, by Dave Curry is still a very good reference for this sort of stuff.
简短的22岁的O'Reilly在Dave Curry上的“在UNIX系统上使用C”这本书仍然是这类内容的一个很好的参考书。
Anyway, here is some code. It is a bit lengthy, as it parses the sample string "/bin/ls /etc"
into the array {"/bin/ls", "/etc", 0}
. But I find using the string format easier and shorter 98% of the time, although this example belies that.
无论如何,这里有一些代码。它有点冗长,因为它将样本字符串“/ bin / ls / etc”解析为数组{“/ bin / ls”,“/ etc”,0}。但我发现使用字符串格式更容易,98%的时间更短,尽管这个例子掩盖了这一点。
This code generates a listing of /etc.
You'll need to change some stuff like e.g. NUMBER()
which is the same asXtNumber()
. And you'll need to decide whether it matches your handling of SIGCHLD
.
此代码生成/ etc的列表。你需要改变一些东西,例如NUMBER()与XtNumber()相同。您需要确定它是否与您对SIGCHLD的处理相匹配。
int main(void) { // list the files in /etc
char buf[100];
FILE *fp;
int pid = spawnfp("/bin/ls /etc", &fp);
while (fgets(buf, sizeof buf, fp))
printf("%s", buf);
fclose(fp); // pclose() replacement
kill(pid, SIGKILL); // pclose() replacement
return 0;
}
The subroutines here are:
这里的子程序是:
static int spawnpipe(const char *argv[], int *fd) // popen() replacement
{
int pid;
int pipe_fds[2];
if (pipe(pipe_fds) < 0)
FatalError("pipe");
switch ((pid = fork()))
{
case -1:
FatalError("fork");
case 0: // child
close(1);
close(2);
dup(pipe_fds[0]);
dup(pipe_fds[1]);
close(pipe_fds[0]);
close(pipe_fds[1]);
execv(argv[0], (char * const *)argv);
perror("execv");
_exit(EXIT_FAILURE); // sic, not exit()
default:
*fd = pipe_fds[0];
close(pipe_fds[1]);
return pid;
}
}
This converts an ascii string to an argv
list, which is probably useless to you:
这会将ascii字符串转换为argv列表,这对您来说可能没用:
Bool convertStringToArgvList(char *p, const char **argv, int maxNumArgs)
{
// Break up a string into tokens, on spaces, except that quoted bits,
// with single-quotes, are kept together, without the quotes. Such
// single-quotes cannot be escaped. A double-quote is just an ordinary char.
// This is a *very* basic parsing, but ok for pre-programmed strings.
int cnt = 0;
while (*p)
{
while (*p && *p <= ' ') // skip spaces
p++;
if (*p == '\'') // single-quote block
{
if (cnt < maxNumArgs)
argv[cnt++] = ++p; // drop quote
while (*p && *p != '\'')
p++;
}
else if (*p) // simple space-delineated token
{
if (cnt < maxNumArgs)
argv[cnt++] = p;
while (*p > ' ')
p++;
}
if (*p)
*p++ = 0; // nul-terminate
}
if (cnt < maxNumArgs)
argv[cnt++] = 0;
return cnt <= maxNumArgs; // check for too many tokens (unlikely)
}
This converts the argument string to tokens and, more importantly, the fd
to an fp
, since the OP requested stdout
:
这会将参数字符串转换为标记,更重要的是,将fd转换为fp,因为OP请求标准输出:
int spawnfp(const char *command, FILE **fpp)
{
const char *argv[100];
int fd, pid;
if (!convertStringToArgvList(strdupa(command), argv, NUMBER(argv)))
FatalError("spawnfp");
pid = spawnpipe(argv, &fd);
*fpp = fdopen(fd, "r");
return pid;
}
#3
#4
1
As others have said, popen
is what you want to use. Something like this...
正如其他人所说,popen是你想要使用的。这样的东西......
#include <iomanip>
#include <iostream>
using namespace std;
const int MAX_BUFFER = 255;
int main()
{
string cmd;
cout << "enter cmd: ";
cin >> cmd;
cout << endl << "running " << cmd << "…" << endl;
string stdout;
char buffer[MAX_BUFFER];
FILE *stream = popen(cmd.c_str(), "r");
while ( fgets(buffer, MAX_BUFFER, stream) != NULL )
stdout.append(buffer);
pclose(stream);
cout << endl << "output: " << endl << stdout << endl;
}
#5
0
I found this answer, which gives popen
a execvp
style interface.
我找到了这个答案,它为popen提供了一个execvp风格的界面。
https://codereview.stackexchange.com/questions/31063/popen-with-array-of-arguments