การยกเลิกการวนซ้ำไม่สิ้นสุด


52

ฉันมีคำสั่งที่ฉันต้องการให้ทำงานอีกครั้งโดยอัตโนมัติในแต่ละครั้งที่มันสิ้นสุดลงดังนั้นฉันจึงทำสิ่งนี้:

while [ 1 ]; do COMMAND; done;

แต่ถ้าฉันหยุดลูปไม่ได้Ctrl-cเพราะมันฆ่าCOMMANDแล้วไม่ใช่ลูปทั้งหมด

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


11
ถ้าฉันทุบตีฉันก็แค่ใช้ Ctrl-Z เพื่อหยุดงานแล้ว "ฆ่า% 1" เพื่อฆ่ามัน
Paul Cager

3
รอสักครู่ ... ไลนัสอ้างว่า: “ เรารู้ดีว่าลินุกซ์นั้นยอดเยี่ยม ... มันวนซ้ำไม่สิ้นสุดใน 5 วินาที” - จริง ๆ ... แค่รออีกไม่กี่วินาทีมันก็จะเสร็จสมบูรณ์
lornix

@ PaulCager ก็ทำงานให้ฉันด้วย! ทำไมมันทำงานที่ Ctrl-C ไม่ได้?
Ciro Santilli 新疆改造中心法轮功六四事件

@cirosantilli มันฆ่างานนอก (bash "wrapper") ในบางสถานการณ์มันจะไม่ฆ่า "คำสั่ง" ในทันทีถ้าคุณทำมันมันอาจแอบผ่านชีวิตไปแม้ว่าพ่อแม่จะตาย แต่วงนั้นตายไปแล้วและนั่นก็เป็นส่วนสำคัญ
orion

คำตอบ:


37

ตรวจสอบสถานะการออกของคำสั่ง หากคำสั่งถูกยกเลิกโดยสัญญาณรหัสออกจะเป็น 128 + หมายเลขสัญญาณ จากเอกสารออนไลน์ของ GNU สำหรับ bash :

สำหรับวัตถุประสงค์ของเชลล์คำสั่งที่ออกโดยมีสถานะจบการทำงานเป็นศูนย์สำเร็จแล้ว สถานะการออกที่ไม่เป็นศูนย์แสดงถึงความล้มเหลว รูปแบบที่ดูเหมือนจะตอบโต้ได้ง่ายนี้ถูกนำมาใช้ดังนั้นจึงมีวิธีหนึ่งที่กำหนดไว้อย่างดีในการบ่งชี้ความสำเร็จและวิธีการที่หลากหลายในการระบุโหมดความล้มเหลวที่หลากหลาย เมื่อคำสั่งยุติการทำงานที่สัญญาณร้ายแรงซึ่งมีค่าเป็น N, Bash จะใช้ค่า 128 + N เป็นสถานะออก

POSIX ยังระบุว่าค่าของคำสั่งที่ยกเลิกโดยสัญญาณนั้นมีค่ามากกว่า 128 แต่ดูเหมือนจะไม่ได้ระบุค่าที่แน่นอนเหมือนที่ GNU ทำ:

สถานะการออกของคำสั่งที่ยกเลิกเนื่องจากได้รับสัญญาณจะต้องรายงานมากกว่า 128

ตัวอย่างเช่นหากคุณขัดจังหวะคำสั่งด้วย control-C รหัสการออกจะเท่ากับ 130 เนื่องจาก SIGINT เป็นสัญญาณ 2 บนระบบ Unix ดังนั้น:

while [ 1 ]; do COMMAND; test $? -gt 128 && break; done

9
มันควรจะกล่าวว่าสิ่งนี้ไม่รับประกันความจริงแล้วหลาย ๆ แอปพลิเคชันจะไม่ทำเช่นนี้
Chris Down

1
@ Kyle Jones: คุณสามารถลิงก์ไปยังเอกสาร POSIX / GNU ที่กล่าวถึงได้หรือไม่
Ciro Santilli 新疆改造中心法轮功六四事件

@cirosantilli เรียบร้อยแล้ว
Kyle Jones

@ KyleJones ขอบคุณ! ยังอยู่ในทางปฏิบัติไม่ทำงานสำหรับคำสั่ง = paplay alert.oggอาจเป็นเพราะการpaplayจัดการสัญญาณหรือไม่
Ciro Santilli 新疆改造中心法轮功六四事件

@cirosantilli ใช่นั่นคือเหตุผล หากกระบวนการจัดการสัญญาณและออกจากกระบวนการนั่นจะแตกต่างจากกระบวนการที่ถูกยกเลิกโดยสัญญาณที่ไม่ได้จัดการ
Kyle Jones

48

คุณสามารถหยุดและทำให้งานของคุณในพื้นหลังในขณะที่มันทำงานโดยใช้+ctrl zจากนั้นคุณสามารถฆ่างานของคุณด้วย:

$ kill %1

ที่ [1] คือหมายเลขงานของคุณ


ดูคำตอบนี้สำหรับคำอธิบายและอื่น ๆ
Skippy le Grand Gourou

2
คำตอบล่าสุดนี้ใช้งานได้ง่าย จำเป็นต้องได้รับการสนับสนุน +1
shivams

คุณช่วยฉันมาก นี่คือสิ่งที่ฉันได้ค้นหาในคำถามนี้ :)
แมก Ruta

18

ฉันจะบอกว่ามันเป็นการดีที่สุดที่จะใส่วนรอบไม่สิ้นสุดลงในสคริปต์และจัดการสัญญาณที่นั่น นี่เป็นจุดเริ่มต้นพื้นฐาน ฉันแน่ใจว่าคุณจะต้องการแก้ไขให้เหมาะสม สคริปต์ใช้trapเพื่อจับctrl- c(หรือSIGTERM) ฆ่าคำสั่ง (ฉันใช้sleepที่นี่เป็นแบบทดสอบ) และออก

cleanup ()
{
kill -s SIGTERM $!
exit 0
}

trap cleanup SIGINT SIGTERM

while [ 1 ]
do
    sleep 60 &
    wait $!
done

4
ดี นี่คือวิธีที่ฉันใช้เคล็ดลับนี้เพื่อสร้างการห่อหุ้ม netcat อัตโนมัติ:trap "exit 0" SIGINT SIGTERM; while true; do netcat -l -p 3000; done
ดักลาส

2
หากคุณเพิ่มtrapวิธีนี้ในสคริปต์ (bash) เดียวกันที่มีการวนซ้ำไม่สิ้นสุดให้ใช้$$แทน$!(ดูที่นี่ )
ardnew

15

Ctrl-Cฉันมักจะเพียงแค่กดลง ไม่ช้าก็เร็วมันจะลงทะเบียนระหว่างCOMMANDและทำให้การwhileวนซ้ำสิ้นสุดลง อาจจะมีวิธีที่ดีกว่า


1
ไม่แน่ใจว่าทำไม แต่มันล้มเหลวสำหรับบางคำสั่งเช่นpaplayในไฟล์ 1s
Ciro Santilli 新疆改造中心法轮功六四事件

มันใช้งานได้สำหรับฉัน
alexandr

นั่นคือแรงเดรัจฉานของวิธีแก้ปัญหาทั้งหมดที่นี่ : /
markroxor

8

หากคุณใช้ bash ด้วย-eจะเป็นการออกในเงื่อนไขข้อผิดพลาด:

#!/bin/bash -e
false # returns 1
echo This won't be printed

7

ทำไมไม่ง่าย ๆ

while [ 1 ]; do COMMAND || break; done;

หรือเมื่อใช้ในสคริปต์

#!/bin/bash
while [ 1 ]; do
  # ctrl+c terminates COMMAND and exits the while loop
  # (assuming COMMAND responds to ctrl+c)
  COMMAND || break
done;

1
ทางออกที่หรูหรามาก แต่สิ่งนี้จะใช้งานไม่ได้หรือไม่ถ้า COMMAND ส่งคืนสถานะการออกจากความสำเร็จเสมอ
howardh

ใช่ @howardh ถูกต้องแล้ว
Dale Anderson

3

ฉันชอบโซลูชันอื่น:

touch .runcmd; while [ -f ".runcmd" ]; do COMMAND; sleep 1; done

เพื่อฆ่าลูปเพียงทำ:

rm .runcmd && kill `pidof COMMAND`

2
  1. คุณสามารถฆ่ากระบวนการด้วย PID ได้ตลอดเวลาโดยไม่จำเป็นต้องปิดเครื่องของคุณ
  2. หากคุณต้องการเรียกใช้บางสิ่งบางอย่างในวงที่ไม่มีที่สิ้นสุดเช่น daemon แล้วคุณควรใส่ไว้ในพื้นหลัง
  3. while : จะสร้างการวนซ้ำไม่สิ้นสุดและช่วยให้คุณเขียน [ 1 ]

    while :; do COMMAND; done &

นี่จะพิมพ์ PID หากคุณออกจากพรอมต์ของคุณโดยใช้ctrl+dงานพื้นหลังจะไม่ออกและคุณสามารถฆ่างานจากที่ใดก็ได้โดยใช้kill PID

หากคุณสูญเสียการติดตาม PID ของคุณคุณสามารถใช้pstree -pa $USERหรือpgrep -fl '.*PROCESS.*'เพื่อช่วยคุณค้นหา


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