Как мне получить путь к процессу в Unix / Linux

138

В среде Windows есть API для получения пути, по которому выполняется процесс. Есть ли что-то подобное в Unix / Linux?

Или есть какой-то другой способ сделать это в этих условиях?

lsalamon
источник

Ответы:

183

В Linux символическая ссылка /proc/<pid>/exeимеет путь к исполняемому файлу. Используйте команду, readlink -f /proc/<pid>/exeчтобы получить значение.

В AIX этот файл не существует. Вы могли бы сравнить cksum <actual path to binary>и cksum /proc/<pid>/object/a.out.

jpalecek
источник
2
sudoесли вывод пуст, некоторые процессы создаются другими пользователями системы.
Lun4i
63

Вы можете легко найти exe этими способами, просто попробуйте сами.

  • ll /proc/<PID>/exe
  • pwdx <PID>
  • lsof -p <PID> | grep cwd
hahakubile
источник
1
Это круто. Я знал, что запустил его из местоположения, которое имело символическую ссылку на исходный исполняемый файл (одна из многих версий). pwdx <PID>дал мне местоположение символической ссылки, чтобы я мог найти логи и правильно остановить процесс.
НурШомик
1
llобычно это псевдоним: alias ll='ls -alF'.
Пабло А
1
Последние два (pwdx и lsof) могут не дать вам правильный результат. Вопрос был о полном пути к исполняемому файлу. pwdx и lsof предоставят вам cwd процесса, а не путь к процессу. Я думаю, что ответ jpalecek является более точным, поскольку исходный запросчик спросил путь к исполняемому файлу, а не программную ссылку, описывающую исполняемый файл.
Шимон
28

Немного поздно, но все ответы были специфичны для Linux.

Если вам нужен также Unix, то вам нужно это:

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

Отредактировано: исправлена ​​ошибка, о которой сообщил Марк Лаката.

Гиперион
источник
Спасибо, что поделились Hiperion, но мне нужно было указать PID и получить путь к exe, возможно ли это с этим кодом?
Noitidart
1
@Noitidart - заменить "/proc/self/exe"наsprintf(foo,"/proc/%d/exe",pid)
Марк Лаката
2
Обратите внимание, что readlink не завершает нулевой результат, поэтому этот код имеет неопределенное поведение.
Марк Лаката
Спасибо @MarkLakata! :)
Noitidart
Спасибо за замечать @MarkLakata
Гиперион
14

Я использую:

ps -ef | grep 786

Замените 786 на свой PID или имя процесса.

пользователь
источник
11

pwdx <process id>

Эта команда будет извлекать путь процесса, из которого она выполняется.

гоби
источник
Вопрос об API для получения информации, но все равно спасибо.
lsalamon
4

В Linux каждый процесс имеет свою собственную папку в /proc. Таким образом, вы можете использовать getpid()pid для запущенного процесса, а затем соединить его с путем, /procчтобы получить нужную папку.

Вот короткий пример на Python:

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

Вот пример и в 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;
}

Скомпилируйте это с:

gcc -Wall -Werror -g -ansi -pedantic process_path.c -oprocess_path 
hyperboreean
источник
Вывод Python для последней версии Ubuntu: >>> import os >>> print os.path.join ('/ proc', str (os.getpid ())) / proc / 24346
Люк Стэнли
3

Там нет "гарантированно работать в любом месте" метод.

Шаг 1 должен проверить argv [0], если программа была запущена по ее полному пути, у этого (как правило) будет полный путь. Если он был запущен по относительному пути, то же самое сохраняется (хотя для этого требуется получить текущий рабочий каталог, используя getcwd ().

Шаг 2, если ничего из вышеперечисленного не выполняется, состоит в том, чтобы получить имя программы, затем получить имя программы из argv [0], затем получить PATH пользователя из среды и пройти через это, чтобы увидеть, есть ли подходящая программа. исполняемый двоичный файл с тем же именем.

Обратите внимание, что argv [0] устанавливается процессом, исполняющим программу, поэтому он не на 100% надежен.

Vatine
источник
2

спасибо: Kiwy
с 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
источник
Это тот факт, что кто-то сделал сценарий этого
Kiwy
1

Вы также можете получить путь к GNU / Linux с помощью (не полностью протестировано):

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

Если вы хотите, чтобы каталог исполняемого файла, возможно, изменил рабочий каталог на каталог процесса (для носителя / данных / и т. Д.), Вам нужно удалить все после последнего /:

*strrchr(buf, '/') = '\0';
/*chdir(buf);*/
Jimmio92
источник
1

Приведенная ниже команда выполняет поиск имени процесса в списке запущенных процессов и перенаправляет команду pid на pwdx, чтобы найти местоположение процесса.

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

Замените «abc» вашим конкретным рисунком.

В качестве альтернативы, если вы можете настроить его как функцию в .bashrc, вам может пригодиться его использование, если вам нужно его часто использовать.

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

Например:

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

18404: /home2/Avro/NIFI

Надеюсь, это поможет кому-нибудь когда-нибудь .....

Arun
источник
-1

Найдите путь к имени процесса

#!/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
источник
4
Пожалуйста, объясните ваш код. Если вы скопировали и вставили его из другого места, пожалуйста, ссылку на источник.
Тим
Этот не очень эффективный код делает получение имени процесса (по сути, строка «PID» является заменой pgrep); в следующей строке он получает путь исполняемого двоичного /proc/$PID/exeфайла ( является символической ссылкой на исполняемый файл); и наконец это повторяет эту символическую ссылку.
Энрико