ฉันเริ่มกระบวนการพื้นหลังจากเชลล์สคริปต์ของฉันและฉันต้องการที่จะฆ่ากระบวนการนี้เมื่อสคริปต์ของฉันเสร็จสิ้น
วิธีรับ PID ของกระบวนการนี้จากเชลล์สคริปต์ของฉัน เท่าที่ฉันเห็นตัวแปร$!
มี PID ของสคริปต์ปัจจุบันไม่ใช่กระบวนการพื้นหลัง
ฉันเริ่มกระบวนการพื้นหลังจากเชลล์สคริปต์ของฉันและฉันต้องการที่จะฆ่ากระบวนการนี้เมื่อสคริปต์ของฉันเสร็จสิ้น
วิธีรับ PID ของกระบวนการนี้จากเชลล์สคริปต์ของฉัน เท่าที่ฉันเห็นตัวแปร$!
มี PID ของสคริปต์ปัจจุบันไม่ใช่กระบวนการพื้นหลัง
คำตอบ:
คุณต้องบันทึก PID ของกระบวนการพื้นหลังในเวลาที่คุณเริ่ม:
foo &
FOO_PID=$!
# do other stuff
kill $FOO_PID
คุณไม่สามารถใช้การควบคุมงานได้เนื่องจากเป็นคุณลักษณะแบบโต้ตอบและเชื่อมโยงกับเทอร์มินัลการควบคุม สคริปต์ไม่จำเป็นต้องมีเทอร์มินัลติดอยู่เลยดังนั้นการควบคุมงานจะไม่สามารถใช้ได้
foo
และ$!
เราได้อะไรบางอย่างจาก pid แทนที่จะfoo
เป็น?
foo
มีคำสั่งหลาย piped (เช่นtail -f somefile.txt | grep sometext
) ในกรณีเช่นนี้คุณจะได้รับ PID ของคำสั่ง grep $!
มากกว่าคำสั่ง tail หากนั่นคือสิ่งที่คุณต้องการ คุณจะต้องใช้jobs
หรือps
ชอบในกรณีนี้
grep
แต่ถ้าคุณฆ่าที่หางจะได้รับ SIGPIPE เมื่อมันพยายามที่จะเขียนไปยังท่อ แต่ทันทีที่คุณพยายามเข้าสู่การจัดการ / ควบคุมกระบวนการที่ยุ่งยาก bash / shell จะค่อนข้างเจ็บปวด
/bin/sh -c 'echo $$>/tmp/my.pid && exec program args' &
- sysfault 24 พ.ย. 53 เวลา 14:28
คุณสามารถใช้jobs -l
คำสั่งเพื่อไปที่ jobL เฉพาะ
^Z
[1]+ Stopped guard
my_mac:workspace r$ jobs -l
[1]+ 46841 Suspended: 18 guard
ในกรณีนี้ 46841 เป็น PID
จากhelp jobs
:
-l รายงาน ID กลุ่มกระบวนการและไดเรกทอรีการทำงานของงาน
jobs -p
เป็นอีกตัวเลือกหนึ่งที่แสดงเฉพาะ PID
$!
หลังจากที่คุณเริ่มมันเป็นแบบพกพาและตรงไปตรงมาในสถานการณ์ส่วนใหญ่ นั่นคือสิ่งที่คำตอบที่ยอมรับในปัจจุบันทำ
jobs -p
กลับเช่นเดียวกับjobs -l
ใน Lubuntu 16.4
$$
เป็น pid ของสคริปต์ปัจจุบัน$!
เป็น pid ของกระบวนการพื้นหลังที่ผ่านมานี่คือตัวอย่างการถอดเสียงจากเซสชัน bash ( %1
หมายถึงหมายเลขลำดับของกระบวนการพื้นหลังตามที่เห็นจากjobs
):
$ echo $$
3748
$ sleep 100 &
[1] 192
$ echo $!
192
$ kill %1
[1]+ Terminated sleep 100
%1
ไม่ส่งคืนกระบวนการพื้นหลังบน Ubuntu ของฉันในขณะที่echo $!
ทำ
วิธีที่ง่ายยิ่งขึ้นในการฆ่ากระบวนการลูกทั้งหมดของสคริปต์ทุบตี:
pkill -P $$
การ-P
ตั้งค่าสถานะทำงานในลักษณะเดียวกันกับpkill
และpgrep
- รับกระบวนการลูกโดยเฉพาะกับpkill
กระบวนการลูกถูกฆ่าและpgrep
พิมพ์รหัส PID ให้กับ stdout
bash -c 'bash -c "sleep 300 &"' &
วิ่งpgrep -P $$
ไม่แสดงอะไรเลยเพราะการนอนหลับจะไม่เป็นลูกโดยตรงของเปลือกหอยของคุณ
$$
อ้างถึงเปลือกปัจจุบัน
bash -c 'bash -c "sleep 300 &"' & ; pgrep -P $$
ฉันไปถึง stdout [1] <pid>. So at least it shows something, but this is probably not the output of
pgrep`
bash -c 'bash -c "sleep 10 & wait $!"' & sleep 0.1; pstree -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
จากนั้นเพียงแค่เรียกใช้เป็น: ./bgkill.sh
ด้วยสิทธิ์ที่เหมาะสมแน่นอน
root@umsstd22 [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.
root@umsstd22 [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
คุณอาจใช้ pstree:
pstree -p user
โดยทั่วไปจะให้การแสดงข้อความของกระบวนการทั้งหมดสำหรับ "ผู้ใช้" และตัวเลือก -p ให้กระบวนการ -ID มันไม่ได้ขึ้นอยู่กับที่ฉันเข้าใจว่าการมีโปรเซสนั้นเป็นของเชลล์ปัจจุบัน นอกจากนี้ยังแสดงให้เห็นถึงส้อม
pgrep
สามารถให้คุณ PID ลูกทั้งหมดของกระบวนการผู้ปกครอง ดังที่ได้กล่าวไว้ก่อนหน้านี้$$
คือ PID ของสคริปต์ปัจจุบัน ดังนั้นหากคุณต้องการสคริปต์ที่ล้างออกหลังจากนี้ควรทำเคล็ดลับ:
trap 'kill $( pgrep -P $$ | tr "\n" " " )' SIGINT SIGTERM EXIT
trap 'pkill -P $$' SIGING SIGTERM EXIT
ดูง่ายกว่า แต่ฉันไม่ได้ทดสอบ
SIG
นำหน้า มันได้รับอนุญาตจาก POSIX แต่เป็นส่วนขยายที่การใช้งานอาจสนับสนุน: pubs.opengroup.org/onlinepubs/007904975/utilities/trap.htmlเปลือก dash ตัวอย่างเช่นไม่