在Linux上,应用程序可以通过查询/proc/self/exe
轻松获得其绝对路径。在FreeBSD上,它更复杂,因为你必须建立一个sysctl调用:
int mib[4];
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PATHNAME;
mib[3] = -1;
char buf[1024];
size_t cb = sizeof(buf);
sysctl(mib, 4, buf, &cb, NULL, 0);
但它仍然完全可行。然而,我找不到在OS X上为命令行应用程序确定这一点的方法。如果您是在应用程序包中运行,则可以通过运行[[NSBundle mainBundle] bundlePath]
来确定它,但由于命令行应用程序不在捆绑包中,因此无效。
(注意:咨询argv[0]
不是一个合理的答案,因为,如果从符号链接启动,argv[0]
将是该符号链接 - 而不是被称为可执行文件的最终路径。{{1}如果一个愚蠢的应用程序使用argv[0]
调用并忘记正确初始化argv,我也会说谎,这是我在野外看到的。)
答案 0 :(得分:51)
函数_NSGetExecutablePath
将返回可执行文件的完整路径(GUI或不是GUI)。该路径可能包含符号链接,“..
”等,但realpath
函数可用于在需要时清除它们。有关详细信息,请参阅man
3
dyld
。
char path[1024];
uint32_t size = sizeof(path);
if (_NSGetExecutablePath(path, &size) == 0)
printf("executable path is %s\n", path);
else
printf("buffer too small; need size %u\n", size);
此函数的秘诀在于Darwin内核在envp
数组创建进程后立即将可执行路径放在进程堆栈上。动态链接编辑器dyld
在初始化时抓取它并保留指向它的指针。该函数使用该指针。
答案 1 :(得分:27)
我相信有更优雅的解决方案,它实际上适用于任何PID,并且还直接返回绝对路径:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <libproc.h>
int main (int argc, char* argv[])
{
int ret;
pid_t pid;
char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
pid = getpid();
ret = proc_pidpath (pid, pathbuf, sizeof(pathbuf));
if ( ret <= 0 ) {
fprintf(stderr, "PID %d: proc_pidpath ();\n", pid);
fprintf(stderr, " %s\n", strerror(errno));
} else {
printf("proc %d: %s\n", pid, pathbuf);
}
return 0;
}
答案 2 :(得分:4)
看起来答案是你不能这样做:
我正在努力实现类似的目标 lsof的功能和收集 一大堆统计和信息 关于运行流程。如果lsof 不是那么慢,我会很高兴坚持 用它。
如果你重新实现lsof,你会发现 这很慢,因为它正在做一个 很多工作。
我想这不是因为lsof 是用户模式,它不仅仅是必须的 扫描任务的地址空间 寻找支持的东西 外部寻呼机。有没有更快 我在这里的时候这样做的方式 内核?
没有。 lsof并不愚蠢;它正在做 它必须做什么。如果你只是想要一个 它的功能的子集,你可能 我想考虑一下 lsof source(可用)和 修剪它以满足你的需要 要求。
出于好奇,
p_textvp
用于 所有?它看起来像是设置为p_textvp
中的父级kern_fork
(和 然后被释放??)但事实并非如此 感受kern_exec
中的任何一个 例程。
p_textvp
未使用。在达尔文, proc不是地址的根 空间;任务是。没有 任务的“vnode”概念 地址空间,因为它不是 必须最初填充 映射一个。如果exec要填充p_textvp,那么 会迎合这样的假设 所有进程都由vnode支持。 然后程序员会认为它 有可能找到一条路 vnode,从那里它是一个短暂的 跳到假设 vnode的当前路径是路径 它是从哪个发起的 字符串上的文本处理可能 导致应用程序包名称... 所有这些都是不可能的 保证没有实质性的惩罚。
答案 3 :(得分:2)
我认为没有保证。 如果argv [0]是符号链接,那么你可以使用readlink()。 如果通过$ PATH执行命令,则可以执行 尝试一些:搜索(getenv(“PATH”)),getenv(“_”),dladdr()
答案 4 :(得分:1)
这已经很晚了,但[[NSBundle mainBundle] executablePath]
适用于非捆绑的命令行程序。
答案 5 :(得分:0)
为什么不简单realpath(argv[0], actualpath);
?确实,realpath有一些限制(在手册页中记录)但它处理符号链接很好。在FreeBSD和Linux上测试
% ls -l foobar lrwxr-xr-x 1 bortzmeyer bortzmeyer 22 Apr 29 07:39 foobar -> /tmp/get-real-name-exe % ./foobar My real path: /tmp/get-real-name-exe
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <libgen.h>
#include <string.h>
#include <sys/stat.h>
int
main(argc, argv)
int argc;
char **argv;
{
char actualpath[PATH_MAX + 1];
if (argc > 1) {
fprintf(stderr, "Usage: %s\n", argv[0]);
exit(1);
}
realpath(argv[0], actualpath);
fprintf(stdout, "My real path: %s\n", actualpath);
exit(0);
}
如果程序是通过PATH启动的,请参阅pixelbeat的解决方案。
答案 6 :(得分:0)