ps: ฉันจะเรียกกระบวนการลูกทั้งหมดซ้ำสำหรับ pid ที่กำหนดซ้ำได้อย่างไร


43

ฉันจะทำให้ต้นไม้กระบวนการทั้งหมดเกิดโดยกระบวนการที่กำหนดให้แสดงเป็นต้นไม้และต้นไม้นั้นไม่มีกระบวนการอื่นได้อย่างไร

ผลลัพธ์เช่นอาจมีลักษณะเช่น

 4378 ?        Ss     0:10 SCREEN
 4897 pts/16   Ss     0:00  \_ -/bin/bash
25667 pts/16   S+     0:00  |   \_ git diff
25669 pts/16   S+     0:00  |       \_ less -FRSX
11118 pts/32   Ss+    0:00  \_ -/bin/bash
11123 pts/32   S+     0:00      \_ vi

psฉันไม่สามารถได้ผลลัพธ์ที่ต้องการได้อย่างหมดจดด้วยพารามิเตอร์

ต่อไปนี้ให้ผลลัพธ์ที่ต้องการ แต่ดูเหมือนว่าจะเกี่ยวข้องกับ:

#!/bin/bash

pidtree() {
  echo -n $1 " "
  for _child in $(ps -o pid --no-headers --ppid $1); do
    echo -n $_child `pidtree $_child` " "
  done
}

ps f `pidtree 4378`

ไม่มีใครมีทางออกที่ง่ายขึ้น?


ไม่ได้คำตอบ ps auxfแต่เริ่มต้นด้วย
jftuga

2
@ jtfuga นี่คือความจริงที่ฉันเริ่มต้น แต่นี่ทำให้ฉันมีกระบวนการทั้งหมดซึ่งเป็นสิ่งที่ฉันไม่ต้องการ
kynan

คำตอบ:


35

นี่pstreeเป็นวิธีแก้ปัญหาที่ดีมาก แต่ก็เงียบเล็กน้อย ฉันใช้ps --forestแทน แต่ไม่ใช่สำหรับPID( -p) เพราะมันพิมพ์เฉพาะกระบวนการที่เฉพาะเจาะจง แต่สำหรับเซสชั่น ( -g) มันสามารถพิมพ์ข้อมูลใด ๆ ที่psสามารถพิมพ์ในต้นไม้ศิลปะ ASCII แฟนซีที่กำหนด-oตัวเลือก

ดังนั้นข้อเสนอแนะของฉันสำหรับปัญหานี้:

ps --forest -o pid,tty,stat,time,cmd -g 2795

หากกระบวนการไม่ใช่ผู้นำเซสชันคุณต้องใช้กลอุบายเพิ่มเติมเล็กน้อย:

ps --forest -o pid,tty,stat,time,cmd -g $(ps -o sid= -p 2795)

สิ่งนี้จะได้รับ session id (SID) ของกระบวนการปัจจุบันก่อนแล้วจึงเรียก ps อีกครั้งด้วย sid นั้น

หากไม่ต้องการส่วนหัวคอลัมน์ให้เพิ่ม '=' หลังจากนิยามคอลัมน์แต่ละคอลัมน์ในตัวเลือก '-o' เช่น:

ps --forest -o pid=,tty=,stat=,time=,cmd= -g $(ps -o sid= -p 2795)

ตัวอย่างการรันและผลลัพธ์:

$ ps --forest -o pid=,tty=,stat=,time=,cmd= -g $(ps -o sid= -p 30085)
27950 pts/36   Ss   00:00:00 -bash
30085 pts/36   S+   00:00:00  \_ /bin/bash ./loop.sh
31888 pts/36   S+   00:00:00      \_ sleep 5

น่าเสียดายที่นี่ใช้งานไม่ได้screenเพราะมันตั้งค่า sid สำหรับหน้าจอสำหรับเด็กแต่ละคนและหลานทุบตีทั้งหมด

เพื่อให้ได้กระบวนการทั้งหมดที่เกิดจากกระบวนการต้นไม้ทั้งหมดจะต้องมีการสร้าง ฉันใช้สำหรับเรื่องนั้น PID => ,child,child...ตอนแรกก็สร้างอาร์เรย์กัญชาจะมีทั้งหมด ในตอนท้ายมันจะเรียกฟังก์ชั่นวนซ้ำเพื่อแยกกระบวนการลูกทั้งหมดของกระบวนการที่กำหนด ผลลัพธ์จะถูกส่งไปยังอีกpsรูปแบบหนึ่งเพื่อจัดรูปแบบผลลัพธ์ PID ที่แท้จริงจะต้องมีการเขียนเป็นอาร์กิวเมนต์เพื่อแทน<PID>:

ps --forest $(ps -e --no-header -o pid,ppid|awk -vp=<PID> 'function r(s){print s;s=a[s];while(s){sub(",","",s);t=s;sub(",.*","",t);sub("[0-9]+","",s);r(t)}}{a[$2]=a[$2]","$1}END{r(p)}')

สำหรับกระบวนการหน้าจอ (pid = 8041) เอาต์พุตตัวอย่างจะมีลักษณะดังนี้:

  PID TTY      STAT   TIME COMMAND
 8041 ?        Ss     0:00 SCREEN
 8042 pts/8    Ss     0:00  \_ /bin/bash
 8092 pts/8    T      0:00      \_ vim test_arg test_server
12473 pts/8    T      0:00      \_ vim
12972 pts/8    T      0:00      \_ vim

ปัญหาเกี่ยวกับเรื่องนี้ (ฉันรู้ว่ามันเป็นคำตอบเก่า) คือ - ตัวเลือกป่าไม้ทำงานได้เฉพาะบน Linux (หรือคำสั่ง "ps" ตาม gnu อื่น ๆ ) Solaris และ MacOS ไม่ชอบ
อาร์มันด์

@TrueY คุณรู้จัก C API ที่สามารถทำได้หรือไม่ ขอขอบคุณ
Bionix1441

Bionix ไม่ขอโทษ ... ฉันอาจจะอ่าน / proc / <PID> ไดเรกทอรีเพื่อสร้างต้นไม้นั้น
TrueY

1
ดูเหมือนว่าเรื่องนี้ควรจะง่ายถ้าpsมีตัวเลือกการตั้งค่าสถานะตัวกรองเพียงเพื่อกรองการสืบทอดทั้งหมดของ PID
CMCDragonkai

24
pstree ${pid}

โดยที่${pid}pid ของกระบวนการพาเรนต์

บน Gentoo Linux pstreeอยู่ในแพ็คเกจ "psmisc" ซึ่งตั้งอยู่ที่http://psmisc.sourceforge.net/


9
ขอบคุณควรได้กล่าวว่าฉันได้ดูpstreeแต่พลาดรูปแบบผลลัพธ์ verbose เพิ่มเติม อย่างไรก็ตามpstree -p <pid>อย่างน้อยพิมพ์ pids ที่อยู่ใกล้พอสมควร
kynan

1
ฉันมีปัญหานี้เช่นกันฉันต้องรวบรวม pids เด็กทั้งหมดซ้ำ แต่ฉันต้องการเพียง pids ดังนั้นฉันจะต้องsedทั้งหมดที่ .. mmm งานนี้ :)pstree -pn 4008 |grep -o "([[:digit:]]*)" |grep -o "[[:digit:]]*"
กุมภ์กุมภ์

11

นี่คือเวอร์ชั่นของฉันที่ทำงานได้ทันที (เพราะpsทำงานเพียงครั้งเดียว) ทำงานในทุบตีและ zsh

pidtree() (
    [ -n "$ZSH_VERSION"  ] && setopt shwordsplit
    declare -A CHILDS
    while read P PP;do
        CHILDS[$PP]+=" $P"
    done < <(ps -e -o pid= -o ppid=)

    walk() {
        echo $1
        for i in ${CHILDS[$1]};do
            walk $i
        done
    }

    for i in "$@";do
        walk $i
    done
)

สิ่งนี้จะพิมพ์ pid ของกระบวนการปัจจุบันซึ่งคุณอาจต้องการหรือไม่ต้องการ ฉันไม่ต้องการกระบวนการปัจจุบันจดทะเบียน (เพียงลูกหลานของกระบวนการปัจจุบัน) ดังนั้นผมเปลี่ยนสคริปต์โดยการย้ายภายในครั้งแรกสำหรับวงและเปลี่ยนไปecho $1 echo $i
Mark Lakata

ฉันเพิ่งจะเขียนฟังก์ชั่นดังกล่าวเมื่อฉันพบสิ่งนี้ นี่เป็นทางออกเดียวที่ทำงานบน MacOS, Linux และ Solaris การทำงานที่ดี. รักที่คุณต้องพึ่งพา ps เพียงครั้งเดียวเพื่อให้งานสำเร็จลุล่วงในความทรงจำ
อาร์มันด์

3

ฉันได้สร้างสคริปต์ทุบตีขนาดเล็กเพื่อสร้างรายการ pid ของกระบวนการลูกของผู้ปกครอง วนซ้ำจนกระทั่งพบกระบวนการลูกสุดท้ายซึ่งไม่มีลูกใด ๆ มันไม่ได้ให้มุมมองแบบต้นไม้แก่คุณ มันเป็นเพียงรายการ pid ทั้งหมด

function list_offspring {
  tp=`pgrep -P $1`          #get childs pids of parent pid
  for i in $tp; do          #loop through childs
    if [ -z $i ]; then      #check if empty list
      exit                  #if empty: exit
    else                    #else
      echo -n "$i "         #print childs pid
      list_offspring $i     #call list_offspring again with child pid as the parent
    fi;
  done
}
list_offspring $1

อาร์กิวเมนต์แรกของ list_offspring เป็น pid หลัก


1
มีคำตอบอื่น ๆ อีกหลายข้อที่ให้สคริปต์ทุบตีที่ไม่ได้พิมพ์ต้นไม้จริงรวมถึงหนึ่งในคำถามนั้น คำตอบ (บางส่วน) ของคุณมีข้อได้เปรียบอะไรบ้างเหนือคำตอบ (บางส่วน) ที่มีอยู่
David Richerby

ฉันใช้การสอบถามซ้ำและเพิ่มคำอธิบายบางอย่าง คิดว่าอาจช่วยใครซักคน มันทำในสิ่งที่ชื่อขอ
Merijn

ฉันชอบการใช้ pgrep ที่นี่เนื่องจาก ps สามารถแตกต่างกันในสายพันธุ์ unix
John Szakmeister

3

ฉันทำงานเพื่อหาวิธีแก้ไขปัญหาเดียวกันนี้อย่างแน่นอน โดยพื้นฐานแล้ว manpage ps ไม่มีเอกสารตัวเลือกที่อนุญาตให้ทำสิ่งที่เราต้องการด้วยคำสั่งเดียว สรุป: จำเป็นต้องใช้สคริปต์

ฉันมากับสคริปต์คล้ายกับของคุณมาก ฉันวางมันลงใน ~ / .bashrc เพื่อที่ฉันจะได้ใช้มันจากเปลือกหอยใด ๆ ก็ได้

pidtree() {
  local parent=$1
  local list=
  while [ "$parent" ] ; do     
    if [ -n "$list" ] ; then
      list="$list,$parent"
    else
      list="$parent"
    fi
    parent=$(ps --ppid $parent -o pid h)
  done
  ps -f -p $list f
}

3

ps -H -g "$pid" -o comm

ไม่ได้เพิ่ม tree ต่อ se มันเป็นเพียงรายการของกระบวนการ

ยกตัวอย่างเช่น

COMMAND
bash
  nvim
    python

-Hตัวเลือกที่จะใช้เพื่อแสดงต้นไม้กระบวนการหรือ"ลำดับชั้นของกระบวนการ (ป่า)"
แอนโธนี Geoghegan

1

ระหว่างทางบนบรรทัดคำสั่ง:

ps -o time,pid,ppid,cmd --forest -g -p $(pgrep -x bash)

มันเอาท์พุท:

    TIME   PID  PPID CMD
00:00:00  5484  5480 bash
00:00:01  5531  5484  \_ emacs -nw .bashrc
00:00:01  2986  2984 /bin/bash
00:00:00  4731  2986  \_ redshift
00:00:00  5543  2986  \_ ps -o time,pid,ppid,cmd --forest -g -p 2986 5484

วิธีที่สง่างามมากขึ้นของวิธีการที่คือการกำหนดฟังก์ชั่นใน.bashrc:

function subps()                                                                                    
{                                                                                                   
    process=$(pgrep -x $1)                                                                                                                                                                     
    ps -o time,pid,ppid,cmd --forest -g -p $process                                                 
}    

จากนั้นในการรันบรรทัดคำสั่ง:

subps bash

1

สิ่งนี้ให้เพียง pid + children pids แต่ละอันในบรรทัดเดียวซึ่งมีประโยชน์สำหรับการประมวลผลเพิ่มเติม

pidtree() {
    for _pid in "$@"; do
        echo $_pid
        pidtree `ps --ppid $_pid -o pid h`
    done
}

0

ฉันทำสคริปที่คล้ายกันโดยอ้างอิงจากข้างบนของฟิลิปป์

pidlist() {
local thispid=$1
local fulllist=
local childlist=
childlist=$(ps --ppid $thispid -o pid h)
for pid in $childlist
do
  fulllist="$(pidlist $pid) $fulllist"
done
echo "$thispid $fulllist"
}

สิ่งนี้จะแสดงผลเด็ก, หลาน, ฯลฯ ทั้งหมด pids ในรูปแบบที่คั่นด้วยช่องว่าง ในทางกลับกันสามารถป้อนให้กับ ps ได้เช่นเดียวกับใน

ps -p $ (pidlist pid )


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.