จะหยุดสคริปต์ bash loop ในเทอร์มินัลได้อย่างไร?


54

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

#!/bin/bash
while :
do
    sl
done

วิธียกเลิกสคริปต์ทุบตีนี้


1
ให้รายละเอียดเพิ่มเติม คุณต้องการที่จะหยุดมันแบบโต้ตอบหรือเป็นโปรแกรม?
จัดการ

1
คุณสามารถกดctrl-cเพื่อส่งSIGINTสัญญาณ (ในเชลล์ส่วนใหญ่) หรือคุณสามารถกดctrl-zที่ส่งSIGTSTPสัญญาณ (ในเชลล์ส่วนใหญ่) ในกรณีที่คุณกดctrl-zกระบวนการที่เกี่ยวข้องจะไม่ถูกฆ่า แต่หยุดชั่วคราว คุณสามารถดำเนินการต่อด้วยfg(อย่างน้อยในbash)
user1146332

ไม่มันไม่ทำงาน!
Yinyanghu

4
ปัญหาไม่ได้เป็นสคริปต์ แต่slคำสั่งที่ฉันเชื่อว่าเป็นคำสั่งบันทึกย่อสำหรับผู้ที่สะกดคำผิดlsแสดงให้เห็นว่ารถไฟกำลังแล่นผ่านไปอย่างช้าๆ เท่าที่ผมรู้ว่ามันดักสัญญาณและต้องถูกฆ่าด้วยSIGINT SIGKILL

1
ขอบคุณ ไม่ได้บรรจุสำหรับ distro ของฉันนั่นคือเหตุผลที่ฉันไม่รู้จัก / พบมัน (ฉันคิดว่าฉันจะไม่ยื่นคำขอ)
จัดการเอกสาร

คำตอบ:


63

โปรแกรมslจงใจละเว้นซึ่งเป็นสิ่งที่ได้รับส่งเมื่อคุณกดSIGINT Ctrl+Cดังนั้นก่อนอื่นคุณต้องบอกว่าslอย่าเพิกเฉยSIGINTโดยการเพิ่ม-eอาร์กิวเมนต์

หากคุณลองทำเช่นนี้คุณจะสังเกตเห็นว่าคุณสามารถหยุดแต่ละคนslแต่พวกเขายังคงทำซ้ำ คุณต้องบอกbashให้ออกหลังจากSIGINTเช่นกัน คุณสามารถทำได้โดยใส่ a trap "exit" INTก่อนลูป

#!/bin/bash
trap "exit" INT
while :
do
    sl -e
done

5
ฉันไม่ได้ติดตั้งเพื่อตรวจสอบ แต่คุณอาจจะสามารถฆ่ามันด้วย SIGQUIT จาก Ctrl- \
derobert

120
  1. กดCtrl-Zเพื่อหยุดสคริปต์
  2. kill %%

%%บอกทุบตีในตัวkillที่คุณต้องการที่จะส่งสัญญาณ (SIGTERM โดยค่าเริ่มต้น) เพื่องานพื้นหลังมากที่สุดเมื่อเร็ว ๆ นี้ที่ลอยอยู่ในเปลือกปัจจุบันไม่ได้ที่จะเป็นกระบวนการที่-ID

คุณยังสามารถระบุงานตามหมายเลขหรือตามชื่อ เช่นเมื่อคุณหยุดงานด้วย ^ Z ทุบตีจะบอกให้คุณทราบว่าหมายเลขงานของมันเป็นอย่างไร[n]+ Stoppedโดยที่nภายในวงเล็บเหลี่ยมเป็นหมายเลขงาน

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการควบคุมงานและในงานฆ่ารันhelp jobs, help fg, help bgและhelp killในทุบตีและค้นหาJOB CONTROL(ตัวพิมพ์ใหญ่ทั้งหมด) หรือjobspecในหน้าคนทุบตี

เช่น

$ ./killme.sh 
./killme.sh: บรรทัด 4: sl: ไม่พบคำสั่ง
./killme.sh: บรรทัด 4: sl: ไม่พบคำสั่ง
./killme.sh: บรรทัด 4: sl: ไม่พบคำสั่ง
./killme.sh: บรรทัด 4: sl: ไม่พบคำสั่ง
./killme.sh: บรรทัด 4: sl: ไม่พบคำสั่ง
...
...
...
./killme.sh: บรรทัด 4: sl: ไม่พบคำสั่ง
^ Z
[1] + หยุด ./killme.sh
$ kill %%
$ 
[1] + สิ้นสุดแล้ว / killme.sh

ในตัวอย่างนี้หมายเลขของงานคือ 1 ดังนั้นkill %1จะทำงานเหมือนกันkill %%

(หมายเหตุ: ฉันไม่ได้slติดตั้งดังนั้นเอาท์พุทก็แค่ "ไม่พบคำสั่ง" ในกรณีของคุณคุณจะได้รับสิ่งที่ผลผลิต sl มันไม่สำคัญ - ^Zระงับและkill %%จะทำงานเหมือนกัน)


3
อีกคำตอบที่ดี!
Yinyanghu

2
BTW สำหรับการดำเนินการลูปอย่างรวดเร็วเช่นนี้ ^ Z อาจเป็นวิธีที่เชื่อถือได้มากกว่าในการฆ่ากระบวนการมากกว่า ^ C ^ C จะถูกส่งไปยังโปรแกรม ( sl) กำลังทำงานอยู่ในลูป แต่สคริปต์จะทำงานต่อไป ... และเริ่มต้นslใหม่ หากคุณกด ^ C สองสามครั้งเร็ว ๆ คุณอาจฆ่าทั้งslสคริปต์และสคริปต์ (ถ้าไม่มีกับดัก SIGINT) ^ Z จะระงับสคริปต์เกือบจะในทันที (ทันทีหากคุณไม่นับเอาต์พุตบัฟเฟอร์ที่ยังคงถูกพิมพ์ไปยังเทอร์มินัลของคุณ) ดังนั้นคุณจึงสามารถฆ่ามันได้ด้วยkill %%
cas

แน่นอน! ฉันต้องบอกว่า " slเป็นโปรแกรมที่สนุก" คราวนี้มันสนุกฉันอีกครั้ง! @ _ @
Yinyanghu

เฉพาะคำตอบที่ดูเหมือนว่าจะใช้งานได้เมื่อลูปไม่ได้ถูกเรียกจากสคริปต์ แต่มาจากบรรทัดคำสั่งโดยตรง
Skippy le Grand Gourou

1
@DrewChapin ฉันจำไม่ได้ว่าเมื่อไหร่ / ที่ไหนที่ฉันรู้เกี่ยวกับมัน - สิ่งที่ฉันรู้ "ตั้งแต่ตลอดกาล" หน้าคนทุบตี (ค้นหาjobspec ) พูดว่า:The symbols %% and %+ refer to the shell's notion of the current job, which is the last job stopped while it was in the foreground or started in the background. The previous job may be referenced using %-. If there is only a single job, %+ and %- can both be used to refer to that job
cas

6

หากคุณต้องการให้ ctrl + c หยุดลูป แต่ไม่เลิกสคริปต์คุณสามารถวาง|| breakหลังจากคำสั่งใดก็ตามที่คุณใช้ ตราบใดที่โปรแกรมที่คุณใช้งานหยุดทำงานด้วย ctrl + c โปรแกรมนี้ก็ใช้งานได้ดี

#!/bin/bash
while :
do
    # ctrl+c terminates sl, but not the shell script
    sl -e || break
done

หากคุณอยู่ในลูปซ้อนคุณสามารถใช้ "break 2" เพื่อออกจากสองระดับเป็นต้น


บวก 1 สำหรับการพัก 2
flyingfinger

3

คุณสามารถยกเลิกสคริปต์นั้นได้โดยกด Ctrl + C จากเทอร์มินัลที่คุณเริ่มสคริปต์นี้ แน่นอนว่าสคริปต์นี้จะต้องทำงานเบื้องหน้าดังนั้นคุณจึงสามารถหยุดมันได้ด้วย Ctrl + C

หรือคุณสามารถค้นหา PID (ID กระบวนการ) ของสคริปต์นั้นในเทอร์มินัลที่เปิดอื่น ๆ โดย:

ps -ef | grep <name_of_the_script>
kill -9 <pid_of_your_running_script>

ทั้งสองวิธีควรทำเคล็ดลับที่คุณขอ


1
ไม่สามารถยกเลิกได้ด้วย Ctrl + C จากเทอร์มินัล ดังนั้นฉันต้องฆ่ามันด้วย ps หรือบนสุด ฉันแค่อยากรู้วิธีฆ่ามันโดยตรง!
Yinyanghu

3

วิธีที่ง่ายที่สุดคือการออกสัญญาณซึ่งมักจะยึดติดอยู่กับQUITControl-Backslash

เมื่อคุณเห็นรถไฟชนการควบคุม - \


1

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

ps -ef


0

วิธีที่จะยุติสคริปต์ทั้งหมดอีกก็จะไปที่พื้นหลังslคำสั่งแล้วสัญญาณกับดักที่จะฆ่ากลุ่มกระบวนการทั้งหมดของสคริปต์ด้วยสัญญาณINTHUP

#!/bin/bash

trap 'trap - INT; kill -s HUP -- -$$' INT
#trap 'trap - INT; kill -s HUP 0' INT

while :
do
   sl & wait
done


-1
while [ true ] 
do

  #check if script is running
  ps | grep script_name.sh | grep -v grep >/dev/null 2>&1

  if [ "$!" != "0" ] ; then
    break
  else

    kill -9 ` ps -ef | grep script_name.sh | cut -d "a" -f 1` 
    echo "kill -9 `get script PID`"

  fi

done

สิ่งนี้น่าจะช่วยได้


2
ทำไมคุณคิดว่า PID ของคำสั่งพื้นหลังสุดท้ายจะเป็น 0
จัดการ

-1

สิ่งที่ฆ่าน่ากลัวเพราะคุณไม่เคยตอนนี้ถ้าสคริปต์ต้องทำงานสองครั้ง และรหัสออกของคุณผิด

while [ something ]; do

 if [ somethingelse ]; then
   echo shut down script with exit code 0
   exit 0
 fi
done

echo something else not happend
exit 2 # Return val important for example for monitoring

ไม่ทำงาน Solution = ใช้ perl ในขณะที่เปิดทุบตีของตัวเอง

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