Linux下C程序用execl+cat打印自身源码,如何无需已知文件路径?
解决C程序调用cat打印自身源码的路径问题
你之前用execl("/bin/pwd", "pwd", NULL)拿不到路径是因为execl会替换当前进程,没法直接捕获它的输出。下面给你几个可行的Linux环境下的解决方案:
方案1:利用/proc/self/exe(最可靠)
Linux的/proc文件系统中,/proc/self/exe是当前进程可执行文件的符号链接,直接读取它就能拿到程序的绝对路径,完全不依赖工作目录或调用方式。
代码示例:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <limits.h> int main() { char exe_path[PATH_MAX]; // 读取符号链接内容 ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path)-1); if (len == -1) { perror("readlink failed"); exit(EXIT_FAILURE); } exe_path[len] = '\0'; // 手动添加字符串结束符 // 调用cat打印自身源码 execl("/bin/cat", "cat", exe_path, NULL); // 如果execl返回,说明调用失败 perror("execl failed"); exit(EXIT_FAILURE); }
方案2:用管道捕获pwd输出(仅适用于程序在当前工作目录运行的情况)
如果必须用pwd获取路径,得通过管道+fork的方式捕获子进程的输出——直接调用execl会替换当前进程,根本没法获取结果。但要注意:这个方法只能拿到当前工作目录,要是程序从其他目录用绝对路径启动,拼接出来的程序路径会出错。
代码示例:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> int main() { int pipefd[2]; pid_t pid; char cwd[PATH_MAX]; // 创建管道 if (pipe(pipefd) == -1) { perror("pipe failed"); exit(EXIT_FAILURE); } pid = fork(); if (pid == -1) { perror("fork failed"); exit(EXIT_FAILURE); } if (pid == 0) { // 子进程:执行pwd,把输出定向到管道 close(pipefd[0]); // 关闭管道读端 dup2(pipefd[1], STDOUT_FILENO); // 将stdout替换为管道写端 execl("/bin/pwd", "pwd", NULL); perror("execl pwd failed"); exit(EXIT_FAILURE); } else { // 父进程:从管道读取pwd的输出 close(pipefd[1]); // 关闭管道写端 ssize_t len = read(pipefd[0], cwd, sizeof(cwd)-1); if (len == -1) { perror("read failed"); exit(EXIT_FAILURE); } // 去掉输出末尾的换行符 cwd[strcspn(cwd, "\n")] = '\0'; // 拼接程序路径(假设编译后的程序名为a.out,根据实际情况修改) char prog_path[PATH_MAX]; snprintf(prog_path, sizeof(prog_path), "%s/%s", cwd, "a.out"); // 调用cat execl("/bin/cat", "cat", prog_path, NULL); perror("execl cat failed"); exit(EXIT_FAILURE); } }
方案3:利用argv[0]和realpath
argv[0]是程序的调用路径(比如./a.out或绝对路径),用realpath可以把相对路径转换成绝对路径。这个方法在大多数作业场景下够用,但如果程序是通过PATH环境变量直接调用的(比如直接输入a.out),且当前目录不在PATH里,可能会出错。
代码示例:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <limits.h> int main(int argc, char *argv[]) { char exe_path[PATH_MAX]; // 把argv[0]转换成绝对路径 if (realpath(argv[0], exe_path) == NULL) { perror("realpath failed"); exit(EXIT_FAILURE); } execl("/bin/cat", "cat", exe_path, NULL); perror("execl failed"); exit(EXIT_FAILURE); }
推荐
优先用方案1,它不依赖任何外部条件,不管程序怎么启动都能准确拿到自身的绝对路径,最适合你的需求。
内容的提问来源于stack exchange,提问作者Draisen
相关产品推荐
相关产品推荐

