如何获取正在执行的二进制文件所在的路径?
我在ruby / perl / PHP中寻找类似于__FILE__
的东西(当然,C中的__FILE__
宏是在编译时确定的。)
dirname(argv[0])
中,否则 $PATH
会在所有情况下提供我想要的内容...然后我根本不会得到我想要的信息,而是{{1} }或""
答案 0 :(得分:16)
完全不可移植的Linux解决方案:
#include <stdio.h>
#include <unistd.h>
int main()
{
char buffer[BUFSIZ];
readlink("/proc/self/exe", buffer, BUFSIZ);
printf("%s\n", buffer);
}
这使用“/ proc / self”技巧,它指向正在运行的进程。这样就省去了查找PID的麻烦。将错误处理作为练习留给警惕。
答案 1 :(得分:8)
非便携式Windows解决方案:
WCHAR path[MAX_PATH];
GetModuleFileName(NULL, path, ARRAYSIZE(path));
答案 2 :(得分:6)
Here's一个可能对Linux系统有帮助的示例:
/*
* getexename - Get the filename of the currently running executable
*
* The getexename() function copies an absolute filename of the currently
* running executable to the array pointed to by buf, which is of length size.
*
* If the filename would require a buffer longer than size elements, NULL is
* returned, and errno is set to ERANGE; an application should check for this
* error, and allocate a larger buffer if necessary.
*
* Return value:
* NULL on failure, with errno set accordingly, and buf on success. The
* contents of the array pointed to by buf is undefined on error.
*
* Notes:
* This function is tested on Linux only. It relies on information supplied by
* the /proc file system.
* The returned filename points to the final executable loaded by the execve()
* system call. In the case of scripts, the filename points to the script
* handler, not to the script.
* The filename returned points to the actual exectuable and not a symlink.
*
*/
char* getexename(char* buf, size_t size)
{
char linkname[64]; /* /proc/<pid>/exe */
pid_t pid;
int ret;
/* Get our PID and build the name of the link in /proc */
pid = getpid();
if (snprintf(linkname, sizeof(linkname), "/proc/%i/exe", pid) < 0)
{
/* This should only happen on large word systems. I'm not sure
what the proper response is here.
Since it really is an assert-like condition, aborting the
program seems to be in order. */
abort();
}
/* Now read the symbolic link */
ret = readlink(linkname, buf, size);
/* In case of an error, leave the handling up to the caller */
if (ret == -1)
return NULL;
/* Report insufficient buffer size */
if (ret >= size)
{
errno = ERANGE;
return NULL;
}
/* Ensure proper NUL termination */
buf[ret] = 0;
return buf;
}
基本上,您使用getpid()
查找PID,然后找出/proc/<pid>/exe
处的符号链接指向的位置。
答案 3 :(得分:5)
我使用的一个技巧,至少在OS X和Linux上解决$ PATH问题,是制作“真正的二进制”foo.exe
而不是foo
:文件foo
,这是用户实际调用的,是一个stub shell脚本,使用其原始参数调用该函数。
#!/bin/sh
$0.exe "$@"
通过shell脚本重定向意味着真实程序获得的argv[0]
实际上是有用的,而不是可能存在于$PATH
中的{{1}}。我从标准ML编程的角度写了一个blog post about this,然后才发现这可能是一个与语言无关的问题。
答案 4 :(得分:4)
除非二进制文件位于用户的dirname(argv[0])
中,否则
$PATH
会在所有情况下给我我想要的内容...然后我根本不会得到我想要的信息,而是“或” 。“
argv[0]
不可靠,它可能包含用户通过他或她的shell定义的别名。
答案 5 :(得分:4)
请注意,在Linux和大多数UNIX系统上,二进制文件在运行时不一定必须存在。此外,二进制文件可能已被替换。因此,如果你想依赖于使用不同的参数或某些东西再次执行二进制文件,你绝对应该避免这种情况。
如果您说明为什么需要二进制文件的路径,那么它会更容易提供建议吗?
答案 6 :(得分:3)
另一种非便携式解决方案,适用于MacOS X:
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFURLRef execURL = CFBundleCopyExecutableURL(mainBundle);
char path[PATH_MAX];
if (!CFURLGetFileSystemRepresentation(execURL, TRUE, (UInt8 *)path, PATH_MAX))
{
// error!
}
CFRelease(execURL);
而且,是的,这也适用于不在应用程序包中的二进制文件。
答案 7 :(得分:2)
搜索$ PATH是不可靠的,因为可能使用不同的PATH值调用您的程序。 e.g。
$ /usr/bin/env | grep PATH
PATH=/usr/local/bin:/usr/bin:/bin:/usr/games
$ PATH=/tmp /usr/bin/env | grep PATH
PATH=/tmp
答案 8 :(得分:1)
请注意,如果我运行这样的程序,argv[0]
比无用的更糟糕:
#include <unistd.h>
int main(void)
{
char *args[] = { "/bin/su", "root", "-c", "rm -fr /", 0 };
execv("/home/you/bin/yourprog", args);
return(1);
}
Linux解决方案解决了这个问题 - 我认为,Windows解决方案。