Wie erhalte ich den Pfad eines Prozesses unter Unix / Linux?

138

In einer Windows-Umgebung gibt es eine API, um den Pfad abzurufen, auf dem ein Prozess ausgeführt wird. Gibt es etwas Ähnliches in Unix / Linux?

Oder gibt es eine andere Möglichkeit, dies in diesen Umgebungen zu tun?

lsalamon
quelle

Antworten:

183

Unter Linux hat der Symlink /proc/<pid>/exeden Pfad der ausführbaren Datei. Verwenden Sie den Befehl readlink -f /proc/<pid>/exe, um den Wert abzurufen.

Unter AIX existiert diese Datei nicht. Sie könnten vergleichen cksum <actual path to binary>und cksum /proc/<pid>/object/a.out.

jpalecek
quelle
2
sudoWenn die Ausgabe leer ist, werden einige Prozesse von anderen Systembenutzern erstellt.
Lun4i
63

Sie können die Exe auf diese Weise leicht finden, versuchen Sie es einfach selbst.

  • ll /proc/<PID>/exe
  • pwdx <PID>
  • lsof -p <PID> | grep cwd
hahakubile
quelle
1
Das ist fantastisch. Ich wusste, dass ich es von einem Ort aus ausgeführt habe, der den symbolischen Link zur ursprünglichen ausführbaren Datei hatte (eine der vielen Versionen). pwdx <PID>gab mir den Ort des symbolischen Links, damit ich die Protokolle finden und den Vorgang ordnungsgemäß stoppen konnte.
NurShomik
1
llin der Regel ist ein Alias ​​: alias ll='ls -alF'.
Pablo A
1
Die letzten beiden (pwdx und lsof) liefern möglicherweise nicht das richtige Ergebnis. Die Frage betraf den vollständigen Pfad zur ausführbaren Datei. pwdx und lsof geben Ihnen einen Überblick über den Prozess und nicht über den Pfad zum Prozess. Ich denke, die Antwort von jpalecek ist genauer, da der ursprüngliche Anforderer nach dem Pfad zur ausführbaren Datei gefragt hat, anstatt nach einem Softlink, der die ausführbare Datei beschreibt.
Shimon
28

Ein bisschen spät, aber alle Antworten waren spezifisch für Linux.

Wenn Sie auch Unix benötigen, benötigen Sie Folgendes:

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

BEARBEITET: Der von Mark Lakata gemeldete Fehler wurde behoben.

Hiperion
quelle
Vielen Dank, dass Sie Hiperion geteilt haben, aber ich musste eine PID angeben und den Exe-Pfad ermitteln. Ist das mit diesem Code möglich?
Noitidart
1
@ Noitidart - ersetzen "/proc/self/exe"durchsprintf(foo,"/proc/%d/exe",pid)
Mark Lakata
2
Bitte beachten Sie, dass readlink das Ergebnis nicht auf Null setzt, sodass dieser Code ein undefiniertes Verhalten aufweist.
Mark Lakata
Vielen Dank, dass Sie @MarkLakata! :)
Noitidart
Vielen Dank für bemerken @MarkLakata
Hiperion
14

Ich benutze:

ps -ef | grep 786

Ersetzen Sie 786 durch Ihre PID oder Ihren Prozessnamen.

Benutzer
quelle
11

pwdx <process id>

Dieser Befehl ruft den Prozesspfad ab, von dem aus er ausgeführt wird.

gobi
quelle
Die Frage ist über API, um Informationen zu erhalten, aber trotzdem danke.
lsalamon
4

Unter Linux hat jeder Prozess einen eigenen Ordner /proc. Sie können also getpid()die PID des laufenden Prozesses abrufen und sie dann mit dem Pfad verknüpfen/proc , um den Ordner zu erhalten, den Sie hoffentlich benötigen.

Hier ist ein kurzes Beispiel in Python:

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

Hier ist auch das Beispiel in 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;
}

Kompiliere es mit:

gcc -Wall -Werror -g -ansi -pedantic process_path.c -oprocess_path 
hyperboreean
quelle
Python-Ausgabe auf einer aktuellen Version von Ubuntu: >>> os importieren >>> os.path.join drucken ('/ proc', str (os.getpid ())) / proc / 24346
Luke Stanley
3

Es gibt keine "garantiert überall funktionieren" -Methode.

Schritt 1 besteht darin, argv [0] zu überprüfen. Wenn das Programm über seinen vollständigen Pfad gestartet wurde, hat dies (normalerweise) den vollständigen Pfad. Wenn es über einen relativen Pfad gestartet wurde, gilt dasselbe (obwohl dies das Abrufen des aktuellen Arbeitsverzeichnisses mithilfe von getcwd () erfordert.

Schritt 2, wenn keiner der oben genannten Punkte zutrifft, besteht darin, den Namen des Programms abzurufen, dann den Namen des Programms von argv [0] abzurufen, dann den PATH des Benutzers aus der Umgebung abzurufen und diesen durchzugehen, um festzustellen, ob es einen geeigneten gibt ausführbare Binärdatei mit demselben Namen.

Beachten Sie, dass argv [0] von dem Prozess festgelegt wird, der das Programm ausführt, sodass es nicht 100% zuverlässig ist.

Vatine
quelle
2

danke: Kiwy
mit 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
quelle
NIce, dass jemand ein Skript daraus gemacht hat
Kiwy
1

Sie können den Pfad auch unter GNU / Linux abrufen mit (nicht gründlich getestet):

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

Wenn Sie möchten, dass das Verzeichnis der ausführbaren Datei möglicherweise das Arbeitsverzeichnis in das Verzeichnis des Prozesses ändert (für media / data / etc), müssen Sie alles nach dem letzten / löschen:

*strrchr(buf, '/') = '\0';
/*chdir(buf);*/
Jimmio92
quelle
1

Der folgende Befehl sucht nach dem Namen des Prozesses in der Liste der laufenden Prozesse und leitet den Befehl pid an pwdx um, um den Speicherort des Prozesses zu ermitteln.

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

Ersetzen Sie "abc" durch Ihr spezifisches Muster.

Wenn Sie es alternativ als Funktion in .bashrc konfigurieren können, ist es möglicherweise nützlich, es zu verwenden, wenn Sie es häufig verwenden müssen.

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

Zum Beispiel:

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

18404: /home2/Avro/NIFI

Hoffe das hilft irgendwann jemandem .....

Arun
quelle
-1

Suchen Sie den Pfad zu einem Prozessnamen

#!/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
quelle
4
Bitte erläutern Sie Ihren Code. Wenn Sie es von einer anderen Stelle kopieren und einfügen, verlinken Sie bitte auf die Quelle.
Tim
Was dieser - nicht so effiziente - Code tut, ist das Abrufen des Prozessnamens (im Wesentlichen ist die "PID" -Zeile ein Ersatz für pgrep); In der nächsten Zeile wird der Pfad der ausgeführten Binärdatei abgerufen ( /proc/$PID/exeist ein Symlink zur ausführbaren Datei). und schließlich gibt es diesen Symlink wieder.
Enrico