173

In a Windows environment there is an API to obtain the path which is running a process. Is there something similar in Unix / Linux?

Or is there some other way to do that in these environments?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
lsalamon
  • 7,998
  • 6
  • 50
  • 63

11 Answers11

232

On Linux, the symlink /proc/<pid>/exe has the path of the executable. Use the command readlink -f /proc/<pid>/exe to get the value.

On AIX, this file does not exist. You could compare cksum <actual path to binary> and cksum /proc/<pid>/object/a.out.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jpalecek
  • 47,058
  • 7
  • 102
  • 144
95

You can find the exe easily by these ways, just try it yourself.

  • ll /proc/<PID>/exe
  • pwdx <PID>
  • lsof -p <PID> | grep cwd
hahakubile
  • 6,978
  • 4
  • 28
  • 18
  • 1
    This is awesome. I knew I ran it from a location which had the symbolic link to the original executable (one of the many versions). `pwdx ` gave me the location of the symbolic link so I could find the logs and stop the process in proper way. – NurShomik Apr 12 '18 at 00:58
  • 2
    `ll` usually is an alias: `alias ll='ls -alF'`. – Pablo Bianchi Aug 21 '18 at 04:19
  • 1
    Last two (pwdx and lsof) may not give you the correct result. The question was about full path to the executable. pwdx and lsof will give you cwd of the process rather than the path to the process. I think the answer of jpalecek is more accurate as the original requestor asked for the path to the executable rather than soft link describing the executable. – Shimon Nov 21 '19 at 12:21
  • This is really useful, however for the last one I seem to need to use `lsof -p | grep -m 1 txt`, as the required process path info seems to be in the first line with `txt`, and not in the `cwd` line? (Applies on macOS and Ubuntu as of date of posting.) – MikeBeaton Jul 04 '21 at 07:31
32

All the answers were specific to Linux.

If you also need Unix, then you need this:

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;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Hiperion
  • 461
  • 6
  • 12
22

pwdx <process id>

This command will fetch the process path from where it is executing.

gobi
  • 511
  • 5
  • 13
21

I use:

ps -ef | grep 786

Replace 786 with your PID or process name.

User
  • 23,729
  • 38
  • 124
  • 207
5

The below command searches for the name of the process in the running process list and redirects the pid to the pwdx command to find the location of the process.

ps -ef | grep "abc" |grep -v grep| awk '{print $2}' | xargs pwdx

Replace "abc" with your specific pattern.

Alternatively, if you could configure it as a function in .bashrc, you may find in handy to use if you need this to be used frequently.

ps1() { ps -ef | grep "$1" |grep -v grep| awk '{print $2}' | xargs pwdx; }

For example:

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

18404: /home2/Avro/NIFI
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Arun
  • 51
  • 1
  • 1
4

In Linux every process has its own folder in /proc. So you could use getpid() to get the pid of the running process and then join it with the path /proc to get the folder you hopefully need.

Here's a short example in Python:

import os
print os.path.join('/proc', str(os.getpid()))

Here's the example in ANSI C as well:

#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;
}

Compile it with:

gcc -Wall -Werror -g -ansi -pedantic process_path.c -oprocess_path 
user
  • 5,335
  • 7
  • 47
  • 63
hyperboreean
  • 8,273
  • 12
  • 61
  • 97
  • Python output on a recent version of Ubuntu: >>> import os >>> print os.path.join('/proc', str(os.getpid())) /proc/24346 – Luke Stanley May 26 '12 at 18:20
3

There's no "guaranteed to work anywhere" method.

Step 1 is to check argv[0], if the program was started by its full path, this would (usually) have the full path. If it was started by a relative path, the same holds (though this requires getting teh current working directory, using getcwd().

Step 2, if none of the above holds, is to get the name of the program, then get the name of the program from argv[0], then get the user's PATH from the environment and go through that to see if there's a suitable executable binary with the same name.

Note that argv[0] is set by the process that execs the program, so it is not 100% reliable.

Vatine
  • 20,782
  • 4
  • 54
  • 70
2

For 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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
zirong
  • 21
  • 2
1

You can also get the path on GNU/Linux with (not thoroughly tested):

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);

If you want the directory of the executable for perhaps changing the working directory to the process's directory (for media/data/etc), you need to drop everything after the last /:

*strrchr(buf, '/') = '\0';
/*chdir(buf);*/
Jimmio92
  • 321
  • 2
  • 9
-1

Find the path to a process name

#!/bin/bash
# @author Lukas Gottschall
PID=`ps aux | grep precessname | grep -v grep | awk '{ print $2 }'`
PATH=`ls -ald --color=never /proc/$PID/exe | awk '{ print $10 }'`
echo $PATH
DwD
  • 23
  • 2
  • 5
    Please explain your code. If you copy and pasted it from elsewhere, please link to the source. – Tim Nov 08 '12 at 08:50
  • 1
    What this -not so efficient- code is doing is getting the process name (essentially, the "PID" line is a replacement for `pgrep`); in the next line it gets the path of the binary being executed (`/proc/$PID/exe` is a symlink to the executable file); and finally it echoes that symlink. – Enrico Jul 19 '16 at 10:34