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?

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.


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

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.


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


11

pwdx <process id>

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


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 

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.


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
}

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

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


-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

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,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.