Jak uzyskać ścieżkę procesu w systemie Unix / Linux

138

W środowisku Windows istnieje API do uzyskania ścieżki, na której jest uruchomiony proces. Czy jest coś podobnego w systemie Unix / Linux?

Czy jest inny sposób, aby to zrobić w tych środowiskach?

lsalamon
źródło

Odpowiedzi:

183

W systemie Linux łącze symboliczne /proc/<pid>/exezawiera ścieżkę do pliku wykonywalnego. Użyj polecenia, readlink -f /proc/<pid>/exeaby uzyskać wartość.

W systemie AIX ten plik nie istnieje. Możesz porównać cksum <actual path to binary>i cksum /proc/<pid>/object/a.out.

jpalecek
źródło
2
sudojeśli wyjście jest puste, niektóre procesy są tworzone przez innych użytkowników systemu.
Lun4i
63

Możesz łatwo znaleźć exe w ten sposób, po prostu spróbuj sam.

  • ll /proc/<PID>/exe
  • pwdx <PID>
  • lsof -p <PID> | grep cwd
hahakubile
źródło
1
To jest niesamowite. Wiedziałem, że uruchomiłem go z lokalizacji, która miała symboliczne łącze do oryginalnego pliku wykonywalnego (jedna z wielu wersji). pwdx <PID>podał mi lokalizację dowiązania symbolicznego, abym mógł znaleźć dzienniki i zatrzymać proces we właściwy sposób.
NurShomik,
1
llzwykle jest aliasem: alias ll='ls -alF'.
Pablo A,
1
Ostatnie dwa (pwdx i lsof) mogą nie dawać poprawnego wyniku. Pytanie dotyczyło pełnej ścieżki do pliku wykonywalnego. pwdx i lsof podają cwd procesu, a nie ścieżkę do procesu. Myślę, że odpowiedź jpalecek jest dokładniejsza, ponieważ pierwotny żądający zapytał o ścieżkę do pliku wykonywalnego, a nie miękki link opisujący plik wykonywalny.
Shimon
28

Trochę późno, ale wszystkie odpowiedzi dotyczyły Linuksa.

Jeśli potrzebujesz również unixa, potrzebujesz tego:

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

    /* the easiest case: we are in 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 in linux, no  guarantee */

    /* check if we have something like execve("foobar", NULL, NULL) */
    if (argv0 == NULL)
    {
        /* we surrender and give 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 use execve: we dont knowe the executable name; we surrender and give instead current path */
    if (getcwd (path, dest_len - 1) == NULL) return NULL;
    strcat  (path, "/");
    return path;
}

ZMIENIONO: Naprawiono błąd zgłoszony przez Marka lakata.

Hiperion
źródło
Dzięki za udostępnienie Hiperion, ale musiałem określić PID i uzyskać jego ścieżkę exe, czy to możliwe z tym kodem?
Noitidart
1
@Noitidart - wymień "/proc/self/exe"sięsprintf(foo,"/proc/%d/exe",pid)
Mark Lakata
2
Należy pamiętać, że readlink nie przerywa wyniku null, więc ten kod ma niezdefiniowane zachowanie.
Mark Lakata
Dziękuję @MarkLakata! :)
Noitidart
Dzięki za zauważenie @MarkLakata
Hiperion
14

Używam:

ps -ef | grep 786

Zastąp 786 swoim PID lub nazwą procesu.

Użytkownik
źródło
11

pwdx <process id>

To polecenie pobierze ścieżkę procesu z miejsca, w którym jest wykonywana.

gobi
źródło
Pytanie dotyczy API, aby uzyskać informacje, ale i tak dziękuję.
lsalamon
4

W systemie Linux każdy proces ma swój własny folder w /proc. Możesz więc użyć getpid()do pobrania pid uruchomionego procesu, a następnie połączyć go ze ścieżką, /procaby uzyskać folder, którego potrzebujesz.

Oto krótki przykład w Pythonie:

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

Oto przykład również w 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;
}

Skompiluj to z:

gcc -Wall -Werror -g -ansi -pedantic process_path.c -oprocess_path 
hiperborejski
źródło
Wyjście Pythona w najnowszej wersji Ubuntu: >>> import os >>> print os.path.join ('/ proc', str (os.getpid ())) / proc / 24346
Luke Stanley
3

Nie ma metody „gwarantowanej pracy w dowolnym miejscu”.

Krok 1 polega na sprawdzeniu argv [0], jeśli program został uruchomiony z pełną ścieżką, miałby (zwykle) pełną ścieżkę. Jeśli został uruchomiony przez ścieżkę względną, te same blokady (chociaż wymaga to pobrania bieżącego katalogu roboczego przy użyciu funkcji getcwd ().

Krok 2, jeśli żadne z powyższych nie zachodzi, polega na uzyskaniu nazwy programu, następnie uzyskaniu nazwy programu z argv [0], a następnie uzyskaniu PATH użytkownika ze środowiska i przejściu przez to, aby sprawdzić, czy jest odpowiedni wykonywalny plik binarny o tej samej nazwie.

Zauważ, że argv [0] jest ustawiana przez proces, który wykonuje program, więc nie jest w 100% wiarygodna.

Watyna
źródło
2

dzięki: Kiwy
z 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
}
zirong
źródło
Dobrze, że ktoś zrobił scenariusz tego
Kiwy,
1

Możesz również pobrać ścieżkę w systemie GNU / Linux za pomocą (nie do końca przetestowane):

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

Jeśli chcesz, aby katalog wykonywalny mógł zostać zmieniony z katalogu roboczego na katalog procesu (dla media / dane / itp.), Musisz porzucić wszystko po ostatnim /:

*strrchr(buf, '/') = '\0';
/*chdir(buf);*/
Jimmio92
źródło
1

Poniższe polecenie wyszukuje nazwę procesu na liście uruchomionych procesów i przekierowuje pid do polecenia pwdx, aby znaleźć lokalizację procesu.

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

Zastąp „abc” określonym wzorcem.

Alternatywnie, jeśli mógłbyś skonfigurować go jako funkcję w .bashrc, może okazać się przydatny w użyciu, jeśli potrzebujesz tego często.

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

Na przykład:

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

18404: /home2/Avro/NIFI

Mam nadzieję, że to komuś kiedyś pomoże .....

Bieg
źródło
-1

Znajdź ścieżkę do nazwy procesu

#!/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
źródło
4
Proszę wyjaśnij swój kod. Jeśli skopiowałeś i wkleiłeś go z innego miejsca, podaj link do źródła.
Tim
To, co robi ten - nie tak efektywny - kod, to pobieranie nazwy procesu (w istocie linia „PID” jest zamiennikiem pgrep); w następnej linii pobiera ścieżkę /proc/$PID/exedo wykonywanego pliku binarnego ( jest dowiązaniem symbolicznym do pliku wykonywalnego); i wreszcie odzwierciedla to dowiązanie symboliczne.
Enrico,