ฉันจะหาเส้นทางของกระบวนการใน Unix / Linux ได้อย่างไร


143

ในสภาพแวดล้อม Windows มี API เพื่อขอรับเส้นทางที่กำลังเรียกใช้กระบวนการ มีสิ่งที่คล้ายกันใน Unix / Linux หรือไม่?

หรือมีวิธีอื่นในการทำเช่นนั้นในสภาพแวดล้อมเหล่านี้หรือไม่?

คำตอบ:


189

บน Linux symlink /proc/<pid>/exeมีเส้นทางของไฟล์ปฏิบัติการ ใช้คำสั่งreadlink -f /proc/<pid>/exeเพื่อรับค่า

บน AIX ไม่มีไฟล์นี้ คุณสามารถเปรียบเทียบและcksum <actual path to binary>cksum /proc/<pid>/object/a.out


2
sudoหากเอาต์พุตว่างกระบวนการบางอย่างจะถูกสร้างขึ้นโดยผู้ใช้ระบบอื่น
Lun4i

66

คุณสามารถค้นหา exe ได้อย่างง่ายดายด้วยวิธีเหล่านี้เพียงแค่ลองด้วยตัวเอง

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

1
นี่มันเจ๋งมาก. ฉันรู้ว่าฉันเรียกใช้จากตำแหน่งที่มีลิงก์สัญลักษณ์ไปยังไฟล์ปฏิบัติการดั้งเดิม (หนึ่งในหลาย ๆ เวอร์ชัน) pwdx <PID>ให้ตำแหน่งของลิงก์สัญลักษณ์เพื่อที่ฉันจะได้พบบันทึกและหยุดกระบวนการอย่างเหมาะสม
NurShomik

1
llมักจะเป็นนามแฝง: alias ll='ls -alF'.
Pablo Bianchi

1
สองรายการสุดท้าย (pwdx และ lsof) อาจให้ผลลัพธ์ที่ไม่ถูกต้อง คำถามเกี่ยวกับเส้นทางแบบเต็มไปยังปฏิบัติการ pwdx และ lsof จะให้ cwd ของกระบวนการแทนที่จะเป็นพา ธ ไปยังกระบวนการ ฉันคิดว่าคำตอบของ jpalecek นั้นแม่นยำกว่าเนื่องจากผู้ร้องขอดั้งเดิมขอเส้นทางไปยังไฟล์ปฏิบัติการแทนที่จะเป็นซอฟต์ลิงก์ที่อธิบายไฟล์ปฏิบัติการ
Shimon

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

แก้ไข:แก้ไขข้อบกพร่องที่รายงานโดย Mark lakata


ขอบคุณสำหรับการแบ่งปัน Hiperion แต่ฉันต้องการระบุ PID และรับเส้นทาง exe รหัสนี้เป็นไปได้หรือไม่
Noitidart

1
@Noitidart - แทนที่"/proc/self/exe"ด้วยsprintf(foo,"/proc/%d/exe",pid)
Mark Lakata

2
โปรดทราบว่า readlink ไม่ทำให้ผลลัพธ์เป็นโมฆะดังนั้นรหัสนี้จึงมีพฤติกรรมที่ไม่ได้กำหนดไว้
Mark Lakata


12

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 

เอาต์พุต Python ใน Ubuntu เวอร์ชันล่าสุด: >>> import os >>> print os.path.join ('/ proc', str (os.getpid ())) / proc / 24346
Luke Stanley

3

ไม่มีวิธี "รับประกันว่าจะใช้ได้ทุกที่"

ขั้นตอนที่ 1 คือการตรวจสอบ argv [0] หากโปรแกรมเริ่มต้นด้วยเส้นทางแบบเต็มสิ่งนี้จะมีเส้นทางแบบเต็ม (โดยปกติ) หากเริ่มต้นโดยพา ธ สัมพัทธ์การเก็บข้อมูลจะเหมือนกัน (แม้ว่าจะต้องได้รับไดเร็กทอรีการทำงานปัจจุบันโดยใช้ getcwd ()

ขั้นตอนที่ 2 หากไม่มีการระงับข้างต้นคือการรับชื่อของโปรแกรมจากนั้นรับชื่อโปรแกรมจาก argv [0] จากนั้นรับ PATH ของผู้ใช้จากสภาพแวดล้อมและดำเนินการตามนั้นเพื่อดูว่ามีเหมาะสมหรือไม่ ไบนารีปฏิบัติการที่มีชื่อเดียวกัน

โปรดทราบว่า argv [0] ถูกกำหนดโดยกระบวนการที่ดำเนินการโปรแกรมดังนั้นจึงไม่น่าเชื่อถือ 100%


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
}

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

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

หวังว่านี่จะช่วยใครบางคนได้บ้าง .....


-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

4
กรุณาอธิบายรหัสของคุณ หากคุณคัดลอกและวางจากที่อื่นโปรดลิงก์ไปยังแหล่งที่มา
ทิม

สิ่งนี้ - ไม่มีประสิทธิภาพ - โค้ดกำลังทำคือการรับชื่อกระบวนการ (โดยพื้นฐานแล้วบรรทัด "PID" คือการแทนที่pgrep); ในบรรทัดถัดไปจะได้รับพา ธ ของไบนารีที่กำลังดำเนินการ ( /proc/$PID/exeเป็น symlink ไปยังไฟล์ปฏิบัติการ) และในที่สุดมันก็สะท้อน symlink นั้น
Enrico
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.