Comment obtenir le chemin d'un processus sous Unix / Linux

138

Dans l'environnement Windows, il existe une API pour obtenir le chemin qui exécute un processus. Y a-t-il quelque chose de similaire sous Unix / Linux?

Ou y a-t-il une autre façon de faire cela dans ces environnements?

lsalamon
la source

Réponses:

183

Sous Linux, le lien symbolique /proc/<pid>/exea le chemin de l'exécutable. Utilisez la commande readlink -f /proc/<pid>/exepour obtenir la valeur.

Sous AIX, ce fichier n'existe pas. Vous pouvez comparer cksum <actual path to binary>et cksum /proc/<pid>/object/a.out.

jpalecek
la source
2
sudosi la sortie est vide, certains processus sont créés par d'autres utilisateurs du système.
Lun4i
63

Vous pouvez trouver facilement l'exe de ces manières, essayez-le vous-même.

  • ll /proc/<PID>/exe
  • pwdx <PID>
  • lsof -p <PID> | grep cwd
hahakubile
la source
1
C'est génial. Je savais que je l'ai exécuté à partir d'un emplacement qui avait le lien symbolique vers l'exécutable d'origine (l'une des nombreuses versions). pwdx <PID>m'a donné l'emplacement du lien symbolique afin que je puisse trouver les journaux et arrêter le processus de manière appropriée.
NurShomik
1
llest généralement un alias: alias ll='ls -alF'.
Pablo A
1
Les deux derniers (pwdx et lsof) peuvent ne pas vous donner le résultat correct. La question portait sur le chemin d'accès complet à l'exécutable. pwdx et lsof vous donneront cwd du processus plutôt que le chemin vers le processus. Je pense que la réponse de jpalecek est plus précise car le demandeur d'origine a demandé le chemin vers l'exécutable plutôt que le lien souple décrivant l'exécutable.
Shimon
28

Un peu tard, mais toutes les réponses étaient spécifiques à Linux.

Si vous avez également besoin d'unix, vous en avez besoin:

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

MODIFIE: Correction du bug signalé par Mark lakata.

Hiperion
la source
Merci d'avoir partagé Hiperion, mais j'avais besoin de spécifier un PID et d'obtenir son chemin exe, est-ce possible avec ce code?
Noitidart
1
@Noitidart - remplacer "/proc/self/exe"parsprintf(foo,"/proc/%d/exe",pid)
Mark Lakata
2
Veuillez noter que readlink ne termine pas le résultat par null, donc ce code a un comportement non défini.
Mark Lakata
Merci @MarkLakata! :)
Noitidart
Merci d'avoir remarqué @MarkLakata
Hiperion
14

J'utilise:

ps -ef | grep 786

Remplacez 786 par votre PID ou nom de processus.

Utilisateur
la source
11

pwdx <process id>

Cette commande récupérera le chemin du processus à partir de l'endroit où elle s'exécute.

gobi
la source
La question concerne l'API pour obtenir des informations, mais merci quand même.
lsalamon
4

Sous Linux, chaque processus a son propre dossier /proc. Vous pouvez donc utiliser getpid()pour obtenir le pid du processus en cours, puis le joindre avec le chemin /procpour obtenir le dossier dont vous avez besoin, espérons-le.

Voici un petit exemple en Python:

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

Voici également l'exemple en 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;
}

Compilez-le avec:

gcc -Wall -Werror -g -ansi -pedantic process_path.c -oprocess_path 
hyperboréen
la source
Sortie Python sur une version récente d'Ubuntu: >>> import os >>> print os.path.join ('/ proc', str (os.getpid ())) / proc / 24346
Luke Stanley
3

Il n'y a pas de méthode «garantie de fonctionner n'importe où».

L'étape 1 consiste à vérifier argv [0], si le programme a été démarré par son chemin complet, il aura (généralement) le chemin complet. S'il a été démarré par un chemin relatif, il en va de même (bien que cela nécessite d'obtenir le répertoire de travail actuel, en utilisant getcwd ().

L'étape 2, si rien de ce qui précède ne tient, consiste à obtenir le nom du programme, puis à obtenir le nom du programme à partir de argv [0], puis à récupérer le PATH de l'utilisateur à partir de l'environnement et à le parcourir pour voir s'il existe un exécutable binaire du même nom.

Notez que argv [0] est défini par le processus qui exécute le programme, il n'est donc pas fiable à 100%.

Vatine
la source
2

merci: Kiwy
avec 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
la source
NIce que quelqu'un en a fait un script
Kiwy
1

Vous pouvez également obtenir le chemin sur GNU / Linux avec (pas complètement testé):

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

Si vous voulez le répertoire de l'exécutable pour peut-être changer le répertoire de travail dans le répertoire du processus (pour media / data / etc), vous devez tout supprimer après le dernier /:

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

La commande ci-dessous recherche le nom du processus dans la liste des processus en cours d'exécution et redirige la commande pid vers pwdx pour trouver l'emplacement du processus.

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

Remplacez "abc" par votre modèle spécifique.

Alternativement, si vous pouvez le configurer comme une fonction dans .bashrc, vous trouverez peut-être pratique à utiliser si vous en avez besoin pour être utilisé fréquemment.

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

Par exemple:

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

18404: /home2/Avro/NIFI

J'espère que cela aidera quelqu'un un jour .....

Arun
la source
-1

Trouvez le chemin vers un nom de processus

#!/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
la source
4
Veuillez expliquer votre code. Si vous le copiez et le collez ailleurs, veuillez créer un lien vers la source.
Tim
Ce que ce code - pas si efficace - fait, c'est obtenir le nom du processus (essentiellement, la ligne "PID" est un remplacement pour pgrep); dans la ligne suivante, il obtient le chemin du binaire en cours d'exécution ( /proc/$PID/exeest un lien symbolique vers le fichier exécutable); et enfin il fait écho à ce lien symbolique.
Enrico