c-运行无效命令时未捕获STDERR输出



我正在尝试捕获运行命令/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, "%sn", 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,并且格式良好的程序通常会向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, "%sn", 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中唯一提到的外壳是关于execlpexecvpexecvpe

如果无法识别文件的标头(尝试的execve(2(失败,返回错误ENOEXEC(,这些函数将执行shell(/bin/sh(,并将文件的路径作为其第一个参数。(如果尝试失败,则不进行进一步搜索。(

最新更新