Đây pstree
là một giải pháp rất tốt, nhưng nó có một chút kín đáo. Tôi sử dụng ps --forest
thay thế. Nhưng không phải cho một PID
( -p
) vì nó chỉ in quy trình cụ thể, mà cho phiên ( -g
). Nó có thể in ra bất kỳ thông tin nào ps
có thể in trong cây nghệ thuật ASCII ưa thích xác định -o
tùy chọn.
Vì vậy, đề nghị của tôi cho vấn đề này:
ps --forest -o pid,tty,stat,time,cmd -g 2795
Nếu quy trình không phải là một nhà lãnh đạo phiên, thì một mẹo nhỏ hơn phải được áp dụng:
ps --forest -o pid,tty,stat,time,cmd -g $(ps -o sid= -p 2795)
Điều này nhận được id phiên (SID) của quy trình hiện tại trước và sau đó gọi lại ps với sid đó.
Nếu các tiêu đề cột không cần thiết, hãy thêm '=' sau mỗi định nghĩa cột trong các tùy chọn '-o', như:
ps --forest -o pid=,tty=,stat=,time=,cmd= -g $(ps -o sid= -p 2795)
Một ví dụ chạy và kết quả:
$ 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
Thật không may, điều này không hoạt động screen
vì nó đặt sid cho mỗi màn hình con và tất cả bash cháu.
Để có được tất cả các quy trình được sinh ra bởi một quy trình, toàn bộ cây cần phải được xây dựng. Tôi đã sử dụng awk cho điều đó. Lúc đầu, nó xây dựng một mảng băm để chứa tất cả PID => ,child,child...
. Cuối cùng, nó gọi một hàm đệ quy để trích xuất tất cả các tiến trình con của một tiến trình đã cho. Kết quả được truyền cho người khác ps
để định dạng kết quả. PID thực tế phải được viết dưới dạng đối số cho awk thay vì <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)}')
Đối với quy trình SCREEN (pid = 8041), đầu ra ví dụ trông như thế này:
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
ps auxf
.