Làm cách nào để có được đường dẫn của một quy trình trong Unix / Linux


138

Trong môi trường Windows, có một API để lấy đường dẫn đang chạy một tiến trình. Có cái gì đó tương tự trong Unix / Linux không?

Hoặc có một số cách khác để làm điều đó trong các môi trường này?

Câu trả lời:


183

Trên Linux, symlink /proc/<pid>/execó đường dẫn thực thi. Sử dụng lệnh readlink -f /proc/<pid>/exeđể nhận giá trị.

Trên AIX, tập tin này không tồn tại. Bạn có thể so sánh cksum <actual path to binary>cksum /proc/<pid>/object/a.out.


2
sudonếu đầu ra trống, một số quy trình được tạo bởi người dùng hệ thống khác.
Lun4i

63

Bạn có thể tìm thấy exe dễ dàng bằng những cách này, chỉ cần tự mình thử nó.

  • ll /proc/<PID>/exe
  • pwdx <PID>
  • lsof -p <PID> | grep cwd

1
Điều này thật tuyệt. Tôi biết tôi đã chạy nó từ một vị trí có liên kết tượng trưng đến tệp thực thi ban đầu (một trong nhiều phiên bản). pwdx <PID>đã cho tôi vị trí của liên kết tượng trưng để tôi có thể tìm thấy các bản ghi và dừng quá trình theo cách thích hợp.
NurShomik

1
llthường là một bí danh : alias ll='ls -alF'.
Pablo A

1
Hai cuối cùng (pwdx và lsof) có thể không cung cấp cho bạn kết quả chính xác. Câu hỏi là về đường dẫn đầy đủ để thực thi. pwdx và lsof sẽ cung cấp cho bạn cwd của quy trình chứ không phải là đường dẫn đến quy trình. Tôi nghĩ rằng câu trả lời của jpalecek là chính xác hơn khi người yêu cầu ban đầu yêu cầu đường dẫn đến tệp thực thi thay vì liên kết mềm mô tả tệp thực thi.
Shimon

28

Hơi muộn một chút, nhưng tất cả các câu trả lời đều dành riêng cho linux.

Nếu bạn cũng cần unix, thì bạn cần điều này:

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

EDITED: Đã sửa lỗi được báo cáo bởi Mark lakata.


Cảm ơn vì đã chia sẻ Hiperion, nhưng tôi cần chỉ định một PID và nhận đường dẫn exe của nó, điều đó có khả thi với mã này không?
Noitidart

1
@Noitidart - thay thế "/proc/self/exe"bằngsprintf(foo,"/proc/%d/exe",pid)
Mark Lakata

2
Xin lưu ý rằng readlink không null kết thúc kết quả, vì vậy mã này có hành vi không xác định.
Đánh dấu Lakata

Cảm ơn bạn @MarkLakata! :)
Noitidart 04/11/2016

Cảm ơn bạn đã chú ý @MarkLakata
Hiperion


11

pwdx <process id>

Lệnh này sẽ tìm nạp đường dẫn quy trình từ nơi nó đang thực thi.


Câu hỏi là về API để có được thông tin, nhưng dù sao cũng cảm ơn.
lsalamon

4

Trong Linux, mọi tiến trình đều có thư mục riêng /proc. Vì vậy, bạn có thể sử dụng getpid()để có được pid của quá trình đang chạy và sau đó tham gia nó với đường dẫn /procđể có được thư mục mà bạn hy vọng cần.

Đây là một ví dụ ngắn trong Python:

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

Đây cũng là ví dụ trong 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;
}

Biên dịch nó với:

gcc -Wall -Werror -g -ansi -pedantic process_path.c -oprocess_path 

Đầu ra Python trên phiên bản Ubuntu gần đây: >>> nhập os >>> in os.path.join ('/ Proc', str (os.getpid ())) / Proc / 24346
Luke Stanley

3

Không có phương pháp "đảm bảo làm việc ở bất cứ đâu".

Bước 1 là kiểm tra argv [0], nếu chương trình được bắt đầu bằng đường dẫn đầy đủ của nó, điều này sẽ (thường) có đường dẫn đầy đủ. Nếu nó được bắt đầu bởi một đường dẫn tương đối, thì giữ nguyên (mặc dù điều này đòi hỏi phải có thư mục làm việc hiện tại, sử dụng getcwd ().

Bước 2, nếu không có cách nào ở trên, là lấy tên của chương trình, sau đó lấy tên của chương trình từ argv [0], sau đó lấy PATH của người dùng từ môi trường và đi qua đó để xem có phù hợp không nhị phân thực thi có cùng tên.

Lưu ý rằng argv [0] được đặt bởi quá trình thực thi chương trình, vì vậy nó không đáng tin cậy 100%.


2

cảm ơn: Kiwy
với 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
}

NIce rằng ai đó đã tạo ra một kịch bản của nó
Kiwy

1

Bạn cũng có thể nhận đường dẫn trên GNU / Linux với (chưa được kiểm tra kỹ lưỡng):

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

Nếu bạn muốn thư mục của tệp thực thi có thể thay đổi thư mục làm việc sang thư mục của tiến trình (đối với phương tiện / dữ liệu / vv), bạn cần bỏ mọi thứ sau lần cuối /:

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

1

Lệnh dưới đây tìm kiếm tên của quy trình trong danh sách quy trình đang chạy và chuyển hướng lệnh pid sang pwdx để tìm vị trí của quy trình.

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

Thay thế "abc" bằng mẫu cụ thể của bạn.

Ngoài ra, nếu bạn có thể định cấu hình nó như một hàm trong .bashrc, bạn có thể thấy hữu ích khi sử dụng nếu bạn cần sử dụng nó thường xuyên.

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

Ví dụ:

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

18404: /home2/Avro/NIFI

Hy vọng điều này sẽ giúp ai đó đôi khi .....


-1

Tìm đường dẫn đến tên quy trình

#!/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
Hãy giải thích mã của bạn. Nếu bạn sao chép và dán nó từ nơi khác, vui lòng liên kết với nguồn.
Tim

Điều này - không hiệu quả - mã đang làm là lấy tên quy trình (về cơ bản, dòng "PID" là một thay thế cho pgrep); trong dòng tiếp theo, nó nhận được đường dẫn của nhị phân được thực thi ( /proc/$PID/exelà một liên kết tượng trưng đến tệp thực thi); và cuối cùng nó lặp lại symlink đó.
Enrico
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.