如何捕获exec命令执行失败时的stderr输出?
捕获execvp执行失败时Bash的详细错误信息
当用C语言的execvp函数执行不存在的命令(比如示例中的bla)时,只能获取到错误返回码和errno(比如返回值2,对应ENOENT),但无法拿到Bash输出的类似「Command 'bla' not found...」的详细标准错误信息。以下是实现捕获该信息的方法:
现有代码示例
基础执行代码
#include <stdio.h> #include <unistd.h> int main(){ char* argv[] = {"bla", NULL}; execvp(argv[0], argv); printf("exec failed\n"); return 0; }
带errno输出的代码
#include <errno.h> #include <stdio.h> #include <unistd.h> int main() { char* argv[] = {"bla", NULL}; execvp(argv[0], argv); printf("exec failed\n %d", errno); return 0; }
期望获取的Bash错误内容
Command 'bla' not found, did you mean: command 'tla' from deb tla (1.3.5+dfsg1-2build1) command 'bwa' from deb bwa (0.7.17-4) command 'bls' from deb bacula-sd (9.4.2-2ubuntu5) Try: sudo apt install <deb name>
解决方案
直接调用execvp找不到命令时,内核仅返回系统级错误,那种友好提示是Bash的内置逻辑,因此需要让Bash来执行目标命令,再捕获它的标准错误输出。可以通过管道(pipe)实现stderr的捕获,具体代码如下:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> int main() { int pipe_fd[2]; pid_t pid; char buf[1024]; ssize_t bytes_read; // 创建管道 if (pipe(pipe_fd) == -1) { perror("pipe failed"); exit(EXIT_FAILURE); } pid = fork(); if (pid == -1) { perror("fork failed"); exit(EXIT_FAILURE); } if (pid == 0) { // 子进程:重定向stderr到管道写端 close(pipe_fd[0]); // 关闭读端 dup2(pipe_fd[1], STDERR_FILENO); // 将stderr指向管道写端 close(pipe_fd[1]); // 关闭原写端 // 调用bash执行命令 char* argv[] = {"bash", "-c", "bla", NULL}; execvp(argv[0], argv); // 如果exec失败,直接退出 perror("execvp failed"); exit(EXIT_FAILURE); } else { // 父进程:读取管道中的stderr内容 close(pipe_fd[1]); // 关闭写端 printf("捕获到的Bash错误信息:\n"); while ((bytes_read = read(pipe_fd[0], buf, sizeof(buf)-1)) > 0) { buf[bytes_read] = '\0'; printf("%s", buf); } close(pipe_fd[0]); // 等待子进程结束 wait(NULL); } return 0; }
代码说明
- 管道创建:用
pipe()创建一对文件描述符,用于父子进程间通信。 - 子进程处理:将标准错误(
STDERR_FILENO)重定向到管道的写端,然后调用execvp执行bash -c "bla",让Bash来处理命令执行逻辑。 - 父进程处理:关闭管道写端,从读端读取Bash输出的错误信息并打印,最后等待子进程退出。
这样就能捕获到Bash针对未知命令输出的详细提示内容。
内容的提问来源于stack exchange,提问作者CIsForCookies
相关产品推荐
相关产品推荐

