2009-12-15 32 views
277

Tôi bắt đầu một quá trình nền từ kịch bản lệnh shell của mình và tôi muốn giết quá trình này khi tập lệnh của tôi kết thúc.Làm thế nào để có được PID của quá trình nền?

Làm cách nào để lấy PID của quá trình này từ tập lệnh shell? Theo như tôi có thể thấy biến $! chứa PID của tập lệnh hiện tại, không phải là quá trình nền.

+5

$! đúng. Bạn có chắc bạn đang bắt đầu tập lệnh trong BG không? mẫu xin vui lòng. – pixelbeat

+4

Có $! đúng. Tôi đã sai. –

+8

$$ chứa tập lệnh PID hiện tại. – HUB

Trả lời

398

Bạn cần lưu PID của backgroun d quy trình tại thời điểm bạn bắt đầu:

foo & 
FOO_PID=$! 
# do other stuff 
kill $FOO_PID 

Bạn không thể sử dụng điều khiển công việc vì đó là tính năng tương tác và được kết nối với thiết bị đầu cuối điều khiển. Một kịch bản sẽ không nhất thiết phải có một thiết bị đầu cuối kèm theo ở tất cả để kiểm soát công việc sẽ không nhất thiết phải có sẵn.

+11

Vì $! trả về pid của quá trình nền cuối cùng. Có thể có điều gì đó bắt đầu giữa 'foo' và' $! ', Và chúng ta nhận được cái gì đó thay vì' foo'? – WiSaGaN

+29

@WiSaGaN: Không. Không có gì giữa những dòng đó. Bất kỳ hoạt động nào khác trên hệ thống sẽ không ảnh hưởng đến điều này. $! sẽ mở rộng đến PID của quá trình nền cuối cùng _ trong shell_ đó. – camh

+6

... sẽ đưa bạn đến nếu 'foo' xảy ra là nhiều lệnh có đường ống (ví dụ' đuôi -f somefile.txt | grep sometext'). Trong trường hợp này, bạn sẽ nhận được PID của lệnh grep từ '$!' Thay vì lệnh đuôi nếu đó là những gì bạn đang tìm kiếm. Bạn sẽ cần phải sử dụng 'jobs' hoặc' ps' hoặc thích trong trường hợp này. –

96

Bạn có thể sử dụng lệnh jobs -l để có được một jobL đặc biệt

^Z 
[1]+ Stopped     guard 

my_mac:workspace r$ jobs -l 
[1]+ 46841 Suspended: 18   guard 

Trong trường hợp này, 46.841 là PID.

Từ help jobs:

-l Báo cáo ID nhóm quy trình và thư mục làm việc của công việc.

jobs -p là một tùy chọn khác chỉ hiển thị các PID.

+0

Để sử dụng điều này trong một kịch bản lệnh shell, bạn phải xử lý đầu ra. – Phil

+6

@Phil Chỉ liệt kê các pids: jobs -p. Để liệt kê pid của một công việc nhất định: jobs -p% 3. Không cần xử lý đầu ra. –

+0

@Erik với các lệnh/đối số khác nhau mà bạn thay đổi bối cảnh nhận xét của tôi. Không có đối số bổ sung đề xuất đầu ra yêu cầu xử lý. Đề nghị cải thiện câu trả lời! – Phil

33
  • $$ là kịch bản hiện tại của pid
  • $! là pid của tiến trình nền cuối cùng

Dưới đây là một bảng mẫu từ một phiên bash (%1 đề cập đến số thứ tự của quá trình nền như đã thấy từ jobs):

$ echo $$ 
3748 

$ sleep 100 & 
[1] 192 

$ echo $! 
192 

$ kill %1 

[1]+ Terminated    sleep 100 
+0

echo '% 1' không trả về tiến trình nền trên Ubuntu của tôi trong khi' echo $! 'Thực hiện – Timo

2

Bạn cũng có thể có thể sử dụng pstree:

pstree -p user 

này thường đưa ra một đại diện văn bản của tất cả các quá trình cho "người sử dụng" và tùy chọn -p cho quá trình-id. Nó không phụ thuộc, theo như tôi hiểu, về việc có các quy trình được sở hữu bởi hệ vỏ hiện tại. Nó cũng cho thấy dĩa.

+1

Để sử dụng điều này trong một kịch bản lệnh shell, bạn sẽ phải xử lý rất nhiều đầu ra. – Phil

3

đây là những gì tôi đã làm. Kiểm tra nó ra, hy vọng nó có thể giúp đỡ.

#!/bin/bash 
# 
# So something to show. 
echo "UNO" > UNO.txt 
echo "DOS" > DOS.txt 
# 
# Initialize Pid List 
dPidLst="" 
# 
# Generate background processes 
tail -f UNO.txt& 
dPidLst="$dPidLst $!" 
tail -f DOS.txt& 
dPidLst="$dPidLst $!" 
# 
# Report process IDs 
echo PID=$$ 
echo dPidLst=$dPidLst 
# 
# Show process on current shell 
ps -f 
# 
# Start killing background processes from list 
for dPid in $dPidLst 
do 
     echo killing $dPid. Process is still there. 
     ps | grep $dPid 
     kill $dPid 
     ps | grep $dPid 
     echo Just ran "'"ps"'" command, $dPid must not show again. 
done 

Sau đó chỉ cần chạy nó như: ./bgkill.sh với các điều khoản đúng đắn tất nhiên

[email protected] [P]:~# ./bgkill.sh 
PID=23757 
dPidLst= 23758 23759 
UNO 
DOS 
UID  PID PPID C STIME TTY   TIME CMD 
root  3937 3935 0 11:07 pts/5 00:00:00 -bash 
root  23757 3937 0 11:55 pts/5 00:00:00 /bin/bash ./bgkill.sh 
root  23758 23757 0 11:55 pts/5 00:00:00 tail -f UNO.txt 
root  23759 23757 0 11:55 pts/5 00:00:00 tail -f DOS.txt 
root  23760 23757 0 11:55 pts/5 00:00:00 ps -f 
killing 23758. Process is still there. 
23758 pts/5 00:00:00 tail 
./bgkill.sh: line 24: 23758 Terminated    tail -f UNO.txt 
Just ran 'ps' command, 23758 must not show again. 
killing 23759. Process is still there. 
23759 pts/5 00:00:00 tail 
./bgkill.sh: line 24: 23759 Terminated    tail -f DOS.txt 
Just ran 'ps' command, 23759 must not show again. 
[email protected] [P]:~# ps -f 
UID  PID PPID C STIME TTY   TIME CMD 
root  3937 3935 0 11:07 pts/5 00:00:00 -bash 
root  24200 3937 0 11:56 pts/5 00:00:00 ps -f 
1

pgrep có thể giúp bạn có được tất cả các PID con của một quá trình cha mẹ. Như đã đề cập trước đó $$ là các tập lệnh PID hiện tại.Vì vậy, nếu bạn muốn có một kịch bản mà dọn dẹp sau khi bản thân, điều này sẽ làm các trick:

trap 'kill $(pgrep -P $$ | tr "\n" " ")' SIGINT SIGTERM EXIT 
+0

Điều này sẽ không giết rất nhiều? – Phil

+0

Có, câu hỏi sẽ không bao giờ đề cập đến việc giữ trẻ em nền _some_ còn sống khi thoát. –

+0

'trap 'pkill -P $$' SIGING SIGTERM EXIT' trông đơn giản hơn, nhưng tôi không kiểm tra nó. – petre

19

Một cách đơn giản hơn để giết tất cả các tiến trình con của một kịch bản bash:

pkill -P $$ 

Các -P cờ hoạt động theo cách tương tự với pkillpgrep - nó nhận được quy trình con, chỉ với pkill quá trình con bị giết và với pgrep các PID con được in thành giá trị.

+0

Câu trả lời hay! Cảm ơn bạn :) –

+0

Bạn được chào đón :) –

+0

Rất thuận tiện! Đây là cách tốt nhất để đảm bảo bạn không để lại các quy trình mở trên nền. – lepe

Các vấn đề liên quan