วิธีฆ่าสคริปต์ที่รันในเทอร์มินัลโดยไม่ปิดเทอร์มินัล (Ctrl + C ไม่ทำงาน)


35

ฉันได้เขียนสคริปต์ทุบตีที่เรียกโปรแกรมอื่น ๆ และดำเนินการคำสั่งมากมาย ฉันรันสคริปต์นี้จากเทอร์มินัล ตอนนี้ฉันต้องการฆ่าสคริปต์

การกดCtrl + Cบางครั้งก็ไม่ตัดฉันคิดว่าเพราะบางครั้งสคริปต์กำลังเรียกใช้งานโปรแกรมอื่นและด้วยเหตุผลบางอย่างที่สัญญาณการฆ่าไม่ทำงาน

อย่างไรก็ตามถ้าฉันปิดหน้าต่างเทอร์มินัลมันจะฆ่าสคริปต์

มีบางอย่างที่ฉันสามารถทำได้ (การรวมกันของแป้นพิมพ์) ที่คล้ายกับการปิดหน้าต่างเทอร์มินัลโดยไม่ต้องปิดหน้าต่างเทอร์มินัลจริง ๆ (ฉันไม่ต้องการสูญเสียประวัติคำสั่งไดเรกทอรีปัจจุบันประวัติเอาท์พุท ฯลฯ )


8
ในกรณีเช่นนี้ฉันลองCtrl + z
kenn

และหลังจากCtrl + zวิ่ง:kill -9 $(pgrep -f your_script.sh)
Noam Manos

คำตอบ:


38

คุณมีตัวเลือกน้อย หนึ่งคือการหยุดสคริปต์ ( CtrlZ) รับ PID ของสคริปต์และส่งSIGKILLไปยังกลุ่มกระบวนการ

เมื่อคำสั่งถูกเรียกใช้ในเชลล์กระบวนการจะเริ่มต้นและชายด์ทั้งหมดของมันเป็นส่วนหนึ่งของกลุ่มกระบวนการเดียวกัน(ในกรณีนี้คือกลุ่มกระบวนการพื้นหน้า) ในการส่งสัญญาณไปยังกระบวนการทั้งหมดในกลุ่มนี้คุณส่งไปยังผู้นำกระบวนการ สำหรับkillคำสั่งนั้นหัวหน้ากระบวนการจะแสดงดังนี้:

kill -PID

ที่ไหนPIDเป็นกระบวนการ ID ของสคริปต์

ตัวอย่าง:

พิจารณาสคริปต์test.shที่เปิดตัวกระบวนการบางอย่าง สมมติว่าคุณใช้มันในเปลือก:

$ ./test.sh

ในอาคารผู้โดยสารแห่งอื่น

$ pgrep test.sh
17802
$ pstree -ps `!!`
pstree -ps `pgrep test.sh`
init(1)───sshd(1211)───sshd(17312)───sshd(17372)───zsh(17788)───test.sh(17802)─┬─dd(17804)
                                                                               ├─sleep(17805)
                                                                               └─yes(17803)

ในกรณีนี้หากต้องการส่งสัญญาณไปยังกลุ่มกระบวนการที่สร้างโดยtest.shคุณต้องทำ:

kill -INT -17802

-INTใช้ในการส่งSIGINTคำสั่งนี้จึงเทียบเท่ากับการกดCtrlCบนเทอร์มินัล ในการส่งSIGKILL:

kill -KILL -17802

คุณจะต้องหยุดสคริปต์หากคุณไม่สามารถเปิดเทอร์มินัลอื่นได้ หากคุณสามารถใช้pgrepเพื่อค้นหา PID

หนึ่งในคำสั่งที่สคริปต์เปิดใช้อาจมีการวางกับดักSIGINTซึ่งอาจเป็นสาเหตุที่CtrlCไม่มีประสิทธิภาพ แต่SIGKILLไม่สามารถติดอยู่และก็มักจะเป็นสุดท้ายรีสอร์ทตัวเลือก คุณอาจต้องการลองSIGTERM( -TERM) ก่อนไปฆ่า ค่าSIGKILLหรือSIGTERMสามารถตั้งค่าเป็นแป้นพิมพ์ลัดวิธีการSIGINTคือ

ทั้งหมดนี้เป็นสิ่งที่สงสัยหากสคริปต์ของคุณไม่มีเส้น Shebang จากคำตอบ SO นี้ :

โดยปกติแล้วเชลล์พาเรนต์จะเดาว่าสคริปต์นั้นถูกเขียนขึ้นสำหรับเชลล์เดียวกัน (เชลล์ที่เหมือนบอร์นน้อยที่สุดจะรันสคริปต์ด้วย / bin / sh, bash จะเรียกใช้เป็น subprocess ของ bash) ...

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

ใช้เส้น Shebang เสมอ


มีการรวมแป้นพิมพ์สำหรับSIGKILLหรือSIGTERM?
becko

@becko ไม่และคุณไม่สามารถตั้งค่าได้หนึ่งรายการ: superuser.com/a/417991/334516
muru

pgrep test.shไม่ส่งคืน PID ให้ฉัน ฉันลองใช้ test.sh แบบง่าย: for i in {1..30}; do sleep 1 echo $i done ในขณะที่test.shกำลังทำงานอยู่ฉันรันpgrep test.shในเทอร์มินัลอื่น แต่ไม่มีอะไรคืนมา เกิดอะไรขึ้น
becko

1
@becko คุณเรียกใช้สคริปต์อย่างไร ลองดูpgrep -f test.shสิ
muru

pgrep -f test.shไม่ทำงานเช่นกัน ฉันรันสคริปต์ด้วย./test.sh
เบ็

6

หากคุณรู้ว่ากระบวนการที่เกี่ยวข้องกับสคริปต์คุณสามารถค้นหา PID ของพวกเขาโดยใช้

 ps -A

จากนั้นใช้หมายเลข PID เพื่อฆ่ากระบวนการที่เกี่ยวข้องโดยใช้

 kill -9 PID_Number

1
มันซับซ้อนเกินไป สคริปต์วางไข่โปรแกรมอื่น ๆ หลายโปรแกรมและโปรแกรมเหล่านี้ยังวางไข่กระบวนการแบบขนาน มันยากมากที่จะติดตามกระบวนการทั้งหมดเหล่านี้ จะต้องมีวิธีแก้ปัญหาที่ง่ายกว่าสิ่งที่คล้ายกับสิ่งที่เกิดขึ้นเมื่อคุณปิดหน้าต่างเทอร์มินัล
becko

คุณลอง pkill -P $$
Harris

1

อย่างที่แฮร์ริสกล่าวว่าคุณสามารถทำงานได้Kill -9 PID_Numberแต่คุณสามารถติดตั้งแพคเกจที่รู้จักกันว่าhtopมีเบราว์เซอร์กระบวนการโต้ตอบที่ทำให้การค้นหากระบวนการเฉพาะง่ายขึ้นมาก htop ยังรองรับกระบวนการฆ่า

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