运行 无效命令时未捕获 STDERR 输出
STDERR output is not being captured when running invalid command
我正在尝试捕获 运行 命令 /bin/lsx -lah /
的输出。
输出应该是:bash: /bin/lsx: no such file or directory
但是,我在 printf()
.
中没有得到任何东西
这是代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define die(e) do { fprintf(stderr, "%s\n", e); exit(EXIT_FAILURE); } while (0);
int main() {
int link[2];
pid_t pid;
char foo[4096];
if (pipe(link)==-1)
die("pipe");
if ((pid = fork()) == -1)
die("fork");
if(pid == 0) {
dup2 (link[1], STDOUT_FILENO);
close(link[0]);
close(link[1]);
execl("/bin/lsx", "ls", "-1", (char *)0);
die("execl");
} else {
close(link[1]);
int nbytes = read(link[0], foo, sizeof(foo));
printf("Output: (%.*s)\n", nbytes, foo);
wait(NULL);
}
return 0;
}
我只是想知道为什么输出没有被捕获并打印在底部 printf()
。
正如 John 所指出的,您只是捕获 stdout
,而不是 stderr
,并且 well-formed 程序通常会将错误消息发送到 stderr
(die
你展示的宏就是一个例子)。
一个快速的解决方案是通过再次调用 dup2
将子进程的 stderr
重定向到它的 stdout
dup2(link[1], STDOUT_FILENO);
dup2(STDOUT_FILENO, STDERR_FILENO);
这会将两个输出流重定向到单个管道。
或者,用两个管道捕获两个流以在它们传播时保持它们的分离。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define die(e) do { fprintf(stderr, "%s\n", e); exit(EXIT_FAILURE); } while (0);
ssize_t push_through(const char *prefix,
FILE *out, int in,
char *buf, size_t bufsz)
{
ssize_t bytes = read(in, buf, bufsz);
if (bytes > 0)
fprintf(out, "%s: (%.*s)\n", prefix, (int) bytes, buf);
return bytes;
}
int main(void)
{
pid_t pid;
int stdout_pipe[2];
int stderr_pipe[2];
char buffer[4096];
if (pipe(stdout_pipe) == -1 || pipe(stderr_pipe) == -1)
die("pipe");
if ((pid = fork()) == -1)
die("fork");
if (pid == 0) {
close(stdout_pipe[0]);
close(stderr_pipe[0]);
dup2(stdout_pipe[1], STDOUT_FILENO);
dup2(stderr_pipe[1], STDERR_FILENO);
close(stdout_pipe[1]);
close(stderr_pipe[1]);
execl("/bin/lsx", "ls", "-1", (char *) NULL);
perror("execl failed because");
die("execl");
} else {
ssize_t outbytes, errbytes;
close(stdout_pipe[1]);
close(stderr_pipe[1]);
do {
outbytes = push_through("out", stdout, stdout_pipe[0],
buffer, sizeof buffer);
errbytes = push_through("err", stderr, stderr_pipe[0],
buffer, sizeof buffer);
} while (outbytes > 0 || errbytes > 0);
wait(NULL);
}
}
如果 execl
失败,调用 perror
打印更详细的错误消息可能会很有用。
注意预期错误
bash: /bin/lsx: no such file or directory
可能被误导了,因为 exec*
函数仅在特定条件下遵从 shell。
man 3 exec
中唯一提到的 shell 是关于 execlp
、execvp
和 execvpe
:
If the header of a file isn't recognized (the attempted execve(2)
failed with the error ENOEXEC), these functions will execute the
shell (/bin/sh) with the path of the file as its first argument.
(If this attempt fails, no further searching is done.)
我正在尝试捕获 运行 命令 /bin/lsx -lah /
的输出。
输出应该是:bash: /bin/lsx: no such file or directory
但是,我在 printf()
.
这是代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define die(e) do { fprintf(stderr, "%s\n", e); exit(EXIT_FAILURE); } while (0);
int main() {
int link[2];
pid_t pid;
char foo[4096];
if (pipe(link)==-1)
die("pipe");
if ((pid = fork()) == -1)
die("fork");
if(pid == 0) {
dup2 (link[1], STDOUT_FILENO);
close(link[0]);
close(link[1]);
execl("/bin/lsx", "ls", "-1", (char *)0);
die("execl");
} else {
close(link[1]);
int nbytes = read(link[0], foo, sizeof(foo));
printf("Output: (%.*s)\n", nbytes, foo);
wait(NULL);
}
return 0;
}
我只是想知道为什么输出没有被捕获并打印在底部 printf()
。
正如 John 所指出的,您只是捕获 stdout
,而不是 stderr
,并且 well-formed 程序通常会将错误消息发送到 stderr
(die
你展示的宏就是一个例子)。
一个快速的解决方案是通过再次调用 dup2
stderr
重定向到它的 stdout
dup2(link[1], STDOUT_FILENO);
dup2(STDOUT_FILENO, STDERR_FILENO);
这会将两个输出流重定向到单个管道。
或者,用两个管道捕获两个流以在它们传播时保持它们的分离。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define die(e) do { fprintf(stderr, "%s\n", e); exit(EXIT_FAILURE); } while (0);
ssize_t push_through(const char *prefix,
FILE *out, int in,
char *buf, size_t bufsz)
{
ssize_t bytes = read(in, buf, bufsz);
if (bytes > 0)
fprintf(out, "%s: (%.*s)\n", prefix, (int) bytes, buf);
return bytes;
}
int main(void)
{
pid_t pid;
int stdout_pipe[2];
int stderr_pipe[2];
char buffer[4096];
if (pipe(stdout_pipe) == -1 || pipe(stderr_pipe) == -1)
die("pipe");
if ((pid = fork()) == -1)
die("fork");
if (pid == 0) {
close(stdout_pipe[0]);
close(stderr_pipe[0]);
dup2(stdout_pipe[1], STDOUT_FILENO);
dup2(stderr_pipe[1], STDERR_FILENO);
close(stdout_pipe[1]);
close(stderr_pipe[1]);
execl("/bin/lsx", "ls", "-1", (char *) NULL);
perror("execl failed because");
die("execl");
} else {
ssize_t outbytes, errbytes;
close(stdout_pipe[1]);
close(stderr_pipe[1]);
do {
outbytes = push_through("out", stdout, stdout_pipe[0],
buffer, sizeof buffer);
errbytes = push_through("err", stderr, stderr_pipe[0],
buffer, sizeof buffer);
} while (outbytes > 0 || errbytes > 0);
wait(NULL);
}
}
如果 execl
失败,调用 perror
打印更详细的错误消息可能会很有用。
注意预期错误
bash: /bin/lsx: no such file or directory
可能被误导了,因为 exec*
函数仅在特定条件下遵从 shell。
man 3 exec
中唯一提到的 shell 是关于 execlp
、execvp
和 execvpe
:
If the header of a file isn't recognized (the attempted execve(2) failed with the error ENOEXEC), these functions will execute the shell (/bin/sh) with the path of the file as its first argument. (If this attempt fails, no further searching is done.)