如何在Unix / Linux中获取进程路径?

175
在Windows环境中,有一个API可以获取运行进程的路径。在Unix/Linux中是否有类似的东西?或者在这些环境中有其他方法可以实现这一功能吗?
11个回答

234

在Linux中,符号链接/proc/<pid>/exe指向可执行文件的路径。使用命令readlink -f /proc/<pid>/exe获取该值。

AIX上,该文件不存在。你可以比较cksum <actual path to binary>cksum /proc/<pid>/object/a.out


7
如果输出为空,则表示一些进程是由其他系统用户创建的。 - Lun4i

95

你可以通过以下方式很容易地找到exe文件,自己试试看。

  • ll /proc/<PID>/exe
  • pwdx <PID>
  • lsof -p <PID> | grep cwd

1
太棒了。我知道我是从一个具有指向原始可执行文件的符号链接的位置运行它的(其中之一版本)。pwdx <PID> 给了我符号链接的位置,所以我可以找到日志并以正确的方式停止进程。 - NurShomik
2
ll通常是一个别名:alias ll='ls -alF' - Pablo Bianchi
1
最后两个命令(pwdx和lsof)可能无法给出正确的结果。问题是关于可执行文件的完整路径。pwdx和lsof将给出进程的当前工作目录(cwd),而不是进程的路径。我认为jpalecek的答案更准确,因为原始请求者要求的是可执行文件的路径,而不是描述可执行文件的软链接。 - Shimon
1
这真的很有用,但是对于最后一个,我似乎需要使用 lsof -p <PID> | grep -m 1 txt,因为所需的进程路径信息似乎在第一行中带有 txt,而不是在 cwd 行中?(适用于发布日期时的 macOS 和 Ubuntu。) - MikeBeaton

32

所有答案都是针对Linux的。

如果您还需要Unix,那么您需要这个:

char * getExecPath (char * path,size_t dest_len, char * argv0)
{
    char * baseName = NULL;
    char * systemPath = NULL;
    char * candidateDir = NULL;

    /* the easiest case: we are on Linux */
    size_t buff_len;
    if (buff_len = readlink ("/proc/self/exe", path, dest_len - 1) != -1)
    {
        path [buff_len] = '\0';
        dirname (path);
        strcat  (path, "/");
        return path;
    }

    /* Ups... not on Linux, no guarantee */

    /* check if we have something like execve("foobar", NULL, NULL) */
    if (argv0 == NULL)
    {
        /* We surrender and give the current path instead */
        if (getcwd (path, dest_len) == NULL) return NULL;
        strcat  (path, "/");
        return path;
    }


    /* argv[0] */
    /* if dest_len < PATH_MAX may cause buffer overflow */
    if ((realpath (argv0, path)) && (!access (path, F_OK)))
    {
        dirname (path);
        strcat  (path, "/");
        return path;
    }

    /* Current path */
    baseName = basename (argv0);
    if (getcwd (path, dest_len - strlen (baseName) - 1) == NULL)
        return NULL;

    strcat (path, "/");
    strcat (path, baseName);
    if (access (path, F_OK) == 0)
    {
        dirname (path);
        strcat  (path, "/");
        return path;
    }

    /* Try the PATH. */
    systemPath = getenv ("PATH");
    if (systemPath != NULL)
    {
        dest_len--;
        systemPath = strdup (systemPath);
        for (candidateDir = strtok (systemPath, ":"); candidateDir != NULL; candidateDir = strtok (NULL, ":"))
        {
            strncpy (path, candidateDir, dest_len);
            strncat (path, "/", dest_len);
            strncat (path, baseName, dest_len);

            if (access(path, F_OK) == 0)
            {
                free (systemPath);
                dirname (path);
                strcat  (path, "/");
                return path;
            }
        }
        free(systemPath);
        dest_len++;
    }

    /* Again, someone has to use execve: we don’t know the executable name; we surrender and instead give the current path */
    if (getcwd (path, dest_len - 1) == NULL)
        return NULL;
    strcat  (path, "/");
    return path;
}

谢谢分享Hiperion,但我需要指定一个PID并获取其exe路径,这个代码可以实现吗? - Noitidart
1
@Noitidart - 请将 "/proc/self/exe" 替换为 sprintf(foo,"/proc/%d/exe",pid) - Mark Lakata
2
请注意,readlink不会在结果中添加空终止符,因此此代码具有未定义的行为。 - Mark Lakata

22

我使用:

ps -ef | grep 786

用你的PID或进程名称替换786。


22

pwdx <进程 ID>

该命令将获取正在执行的进程路径。


1
问题是关于获取信息的API,不过还是谢谢。 - lsalamon

5
下面的命令在运行的进程列表中搜索进程名称,并将pid重定向到pwdx命令以查找进程的位置。
ps -ef | grep "abc" |grep -v grep| awk '{print $2}' | xargs pwdx

将“abc”替换为你特定的模式。
或者,如果你能够在.bashrc中配置它作为一个函数,当你需要频繁使用时,你可能会发现它很方便。
ps1() { ps -ef | grep "$1" |grep -v grep| awk '{print $2}' | xargs pwdx; }

例如:

[admin@myserver:/home2/Avro/AvroGen]$ ps1 nifi

18404: /home2/Avro/NIFI

这将为您提供pid的当前工作目录,而不是进程的绝对路径。 - northernwind

4
在Linux中,每个进程都有自己的文件夹在/proc目录下。因此,你可以使用getpid()来获取正在运行进程的pid,然后将其与路径/proc连接起来,以获取你所需的文件夹。
以下是Python的简短例子:
import os
print os.path.join('/proc', str(os.getpid()))

这里也有一个ANSI C的例子:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>


int
main(int argc, char **argv)
{
    pid_t pid = getpid();

    fprintf(stdout, "Path to current process: '/proc/%d/'\n", (int)pid);

    return EXIT_SUCCESS;
}

使用以下命令进行编译:

gcc -Wall -Werror -g -ansi -pedantic process_path.c -oprocess_path 

Python在最新版本的Ubuntu上的输出:
import os print os.path.join('/proc', str(os.getpid())) /proc/24346
- Luke Stanley

3
没有一种“保证在任何地方都能正常工作”的方法。
第一步是检查argv[0],如果程序是通过完整路径启动的,则通常会有完整路径。如果是通过相对路径启动的,同样适用(尽管这需要使用getcwd()获取当前工作目录)。
第二步,如果以上都不适用,则获取程序的名称,然后从argv[0]获取程序的名称,然后从环境中获取用户的PATH,并查看其中是否有具有相同名称的适当可执行二进制文件。
请注意,argv[0]由执行程序的进程设置,因此它并非100%可靠。

2

对于AIX

getPathByPid()
{
    if [[ -e /proc/$1/object/a.out ]]; then
        inode=`ls -i /proc/$1/object/a.out 2>/dev/null | awk '{print $1}'`
        if [[ $? -eq 0 ]]; then
            strnode=${inode}"$"
            strNum=`ls -li /proc/$1/object/ 2>/dev/null | grep $strnode | awk '{print $NF}' | grep "[0-9]\{1,\}\.[0-9]\{1,\}\."`
            if [[ $? -eq 0 ]]; then
                # jfs2.10.6.5869
                n1=`echo $strNum|awk -F"." '{print $2}'`
                n2=`echo $strNum|awk -F"." '{print $3}'`
                # brw-rw----    1 root     system       10,  6 Aug 23 2013  hd9var
                strexp="^b.*"$n1,"[[:space:]]\{1,\}"$n2"[[:space:]]\{1,\}.*$"    # "^b.*10, \{1,\}5 \{1,\}.*$"
                strdf=`ls -l /dev/ | grep $strexp | awk '{print $NF}'`
                if [[ $? -eq 0 ]]; then
                    strMpath=`df | grep $strdf | awk '{print $NF}'`
                    if [[ $? -eq 0 ]]; then
                        find $strMpath -inum $inode 2>/dev/null
                        if [[ $? -eq 0 ]]; then
                            return 0
                        fi
                    fi
                fi
            fi
        fi
    fi
    return 1
}

Courtesy Kiwy.


1

你也可以在GNU/Linux上使用以下命令获取路径(未经全面测试):

char file[32];
char buf[64];
pid_t pid = getpid();
sprintf(file, "/proc/%i/cmdline", pid);
FILE *f = fopen(file, "r");
fgets(buf, 64, f);
fclose(f);

如果您想获取可执行文件的目录,以便更改工作目录到进程的目录(用于媒体/数据等),则需要删除最后一个 / 之后的所有内容:
*strrchr(buf, '/') = '\0';
/*chdir(buf);*/

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接