กดปุ่มใดก็ได้เพื่อหยุดเชลล์สคริปต์ชั่วคราวกดอีกครั้งเพื่อดำเนินการต่อ


11

ฉันเขียนเชลล์สคริปต์เพื่อทดสอบ API ที่คัดลอกไฟล์และสะท้อนความคืบหน้าหลังจากแต่ละไฟล์

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

ฉันจะเพิ่มสิ่งนี้ลงในสองสามบรรทัดได้อย่างไร

คำตอบ:


12

คุณไม่จำเป็นต้องเพิ่มบางอย่างในสคริปต์ของคุณ เชลล์อนุญาตให้ใช้ฟังก์ชันดังกล่าวได้

  • เริ่มสคริปต์ของคุณในเทอร์มินัล
  • ในขณะที่มีการทำงานและมีการปิดกั้นการใช้ขั้ว-ctrl zเทอร์มินัลจะถูกปล่อยอีกครั้งและคุณเห็นข้อความว่ากระบวนการหยุดทำงาน (ตอนนี้อยู่ในสถานะ porcess Tหยุดทำงาน)
  • ตอนนี้ทำสิ่งที่คุณต้องการ นอกจากนี้คุณยังสามารถเริ่มต้นกระบวนการอื่น ๆ / สคริปต์และหยุดพวกเขาด้วย-ctrlz
  • พิมพ์jobsเทอร์มินัลหรือรายการงานที่หยุดทั้งหมด
  • หากต้องการให้สคริปต์ของคุณดำเนินการต่อให้พิมพ์fg(เบื้องหน้า) จะดำเนินการงานกลับสู่กลุ่มกระบวนการส่วนหน้าและงานจะยังคงทำงานต่อไป

ดูตัวอย่าง:

root@host:~$ sleep 10 # sleep for 10 seconds
^Z
[1]+  Stopped                 sleep 10
root@host:~$ jobs # list all stopped jobs
[1]+  Stopped                 sleep 10
root@host:~$ fg # continue the job
sleep 10
root@host:~$ # job has finished

อย่างที่คุณพูดถ้าฉันเรียกใช้sleep 10; notify-send helloแล้วกด CTRL + Z เพื่อหยุดnotify-send helloรับการดำเนินการ หากคำสั่งที่สองได้รับการดำเนินการว่าทำไมกระบวนการแรกหยุดลง? หลังจากนั้นถ้าfgฉันพิมพ์ไม่เห็นสิ่งใดเกิดขึ้นซึ่งเห็นได้ชัดตั้งแต่คำสั่งที่สองได้รับการดำเนินการแล้ว
Edward Torvalds

@edwardtorvalds เนื่องจากทั้งสองคำสั่งแยกกัน ในสคริปต์พวกเขาจะอยู่ใน subshell เขียนไว้ในสคริปต์อย่างง่ายและรันสคริปต์ จากนั้น ctrl-z เพื่อหยุดและคุณจะเห็นคำสั่งที่สองไม่ได้ถูกเรียกใช้จนกว่าคำสั่งแรกจะเสร็จสิ้น เขียนเป็นเหมือนการเขียนcmd; cmd; cmd; cmd <newline> cmd <newline> ...อีกทางเลือกหนึ่งสำหรับสคริปต์ที่คุณสามารถเขียน( cmd; cmd; cmd; )ได้มันจะทำงานเหมือนสคริปต์แบ็คเอนด์ของ subshell ที่สร้างขึ้นโดย(
chaos

sleep 10ฉันยังพยายาม เมื่อฉันกด CTRL + Z หลังจาก 3 วินาทีและกลับมาทำงานต่อหลังจากนั้นสองสามวินาทีและสังเกตว่าคำสั่ง sleep นั้นตายในเวลาน้อยกว่า 7 วินาที ซึ่งตรงกันข้ามกับสิ่งที่คุณพูดตั้งแต่คำสั่ง nevers หยุดทำงานมันก็แค่ทำงานในพื้นหลัง
Edward Torvalds

@edwardtorvalds ฉันสังเกตเห็นว่าเกินไป ... ไม่สมเหตุสมผล ฉันstraceงคำสั่งและพบว่าสายระบบที่ใช้เป็นsleep nanosleep()ดูเหมือนว่าจะเป็นพฤติกรรมที่กำหนดของระบบnanosleepโทร restart_syscall()รีสตาร์ทการเรียกระบบที่ถูกขัดจังหวะด้วยอาร์กิวเมนต์เวลาที่ปรับให้เหมาะสมกับบัญชีสำหรับเวลาที่ผ่านไปแล้ว (รวมถึงเวลาที่กระบวนการหยุดทำงานโดยสัญญาณ) อ่าน manpage ที่: man7.org/linux/man-pages/man2/restart_syscall.2.html
ความโกลาหล

หมายเหตุหลายข้อเพื่อให้ @chaos ตอบคำถาม (อย่าลังเลที่จะรวมไว้ใน): เมื่อมีใครทำ ctrl-Z งานจะถูกระงับ ("หยุด") ดังนั้นจึงไม่ทำงานในขณะนี้รอให้คุณตัดสินใจที่จะดำเนินการต่อ ในเบื้องหน้า (เช่นfg %1) หรือพื้นหลัง (เช่น: bg %1) (ถ้างานให้ 1 หมายเลขเท่านั้นนั่นคือเพียง 1 กระบวนการที่ถูกระงับชั่วคราวดังที่ในตัวอย่างความโกลาหลที่แสดงให้เห็น: เท่านั้น[1]+ stopped sleep 10คุณสามารถละเว้น%nส่วนนั้นได้หากมีกระบวนการพื้นหลังหลายกระบวนการ (การเรียกใช้หรือหยุด) คุณต้องกำหนดสิ่งที่คุณต้องการ ด้วย: %n(เช่น: fg %2 มีประวัติย่อ 2% ในเบื้องหน้า))
Olivier Dulac

6

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

คุณสามารถใช้ได้

read -tเพื่อตั้งค่าการหมดเวลาสำหรับการอ่าน
read -nเพื่ออ่านหนึ่งตัวอักษร (อย่างมีประสิทธิภาพเพียงแค่กดปุ่มใด ๆ ) เพื่อดำเนินการต่อสคริปต์

เนื่องจากคุณไม่ได้ระบุรหัสใด ๆ ด้านล่างเป็นตัวอย่างของวิธีการใช้งาน
หากกด q จะread -n1ป้องกันไม่ให้สคริปต์ดำเนินต่อไปจนกว่าจะกดปุ่ม
เมื่อกดปุ่มการตรวจสอบจะถูกรีเซ็ตและสคริปต์จะดำเนินการต่อในลูปตามปกติ

while [[ true ]]; do
    read -t2 -n1 check
    if [[ $check == "q" ]];then
        echo "pressed"
        read -n1
        check=""
    else
        echo "not pressed"
    fi
echo "Doing Something"
done

คุณสามารถเพิ่มลงstty -echoในส่วนเริ่มต้นของส่วนและส่วนstty echoท้ายเพื่อป้องกันการพิมพ์ไม่ให้เลอะเอาท์พุทหน้าจอ


@ mikeserv ฉันไม่คิดว่า op สนใจสิ่งที่อ่านพวกเขาเพียงต้องการหยุดชั่วคราวและเล่นสคริปต์ต่อคุณหมายถึงอะไรโดยบันทึกการตั้งค่าเทอร์มินัลเช่นกันฉันแค่เปลี่ยนไปหนึ่งครั้ง

1
@ mikeserv อ่าใช่ฉันแค่คิดว่า stdin ทั้งหมดจะมาจากผู้ใช้

1

ด้วยddคุณสามารถอ่านไบต์เดียวจากไฟล์ได้อย่างน่าเชื่อถือ กับsttyคุณสามารถกำหนดminจำนวนไบต์ให้มีคุณสมบัติในการอ่านเทอร์มินัลและtimeออกเป็นสิบวินาที รวมสองสิ่งนี้เข้าด้วยกันและคุณสามารถทำได้โดยไม่ต้องใช้ความsleepคิดทั้งหมดและให้เวลาในการอ่านของสถานีทำงานเพื่อคุณ

s=$(stty -g </dev/tty)
(while stty raw -echo isig time 20 min 0;test -z "$(
dd bs=1 count=1 2>/dev/null; stty "$s")" || (exec sh)
do echo "$SECONDS:" do your stuff here maybe                             
   echo  no sleep necessary, I think                                                          
   [ "$((i+=1))" -gt 10 ] && exit                                                             
done       
) </dev/tty

นั่นเป็นตัวอย่างเล็ก ๆ น้อย ๆwhileที่ฉันล้อเลียนเพื่อให้คุณลอง ทุกสองวินาทีddหมดเวลากับความพยายามในการอ่านstdin- เปลี่ยนเส้นทางจาก/dev/tty - และwhileลูปลูป นั้นหรือdd ไม่หมดเวลาเพราะคุณกดปุ่ม - ในกรณีที่เปลือกโต้ตอบถูกเรียก

นี่คือการทดสอบการทำงาน - ตัวเลขที่พิมพ์ที่ส่วนหัวของแต่ละบรรทัดคือค่าของตัวแปรเชลล์$SECONDS:

273315: do your stuff here maybe
no sleep necessary, I think
273317: do your stuff here maybe
no sleep necessary, I think
273319: do your stuff here maybe
no sleep necessary, I think
273321: do your stuff here maybe
no sleep necessary, I think
sh-4.3$ : if you press a key you get an interactive shell
sh-4.3$ : this example loop quits after ten iterations
sh-4.3$ : or if this shell exits with a non-zero exit status
sh-4.3$ : and speaking of which, to do so you just...
sh-4.3$ exit
exit
273385: do your stuff here maybe
no sleep necessary, I think
273387: do your stuff here maybe
no sleep necessary, I think
273389: do your stuff here maybe
no sleep necessary, I think
273391: do your stuff here maybe
no sleep necessary, I think
273393: do your stuff here maybe
no sleep necessary, I think
273395: do your stuff here maybe
no sleep necessary, I think
273397: do your stuff here maybe
no sleep necessary, I think

คุณไม่ควรใช้stty saneหลังจากเปลี่ยนการตั้งค่า stty ฉันอาจจะผิด แต่ดูเหมือนว่าคุณจะรีเซ็ตทุกที่หรือไม่

@Jidder - s=$(stty -g </dev/tty)ไม่มีฉันบันทึกสถานะของสถานีที่ด้านบนของสคริปต์ด้วย ทันทีหลังจากที่เรียกฉันแล้วเรียกคืนได้ด้วยdd stty "$s"สถานะเทอร์มินัลไม่สนใจเกี่ยวกับ subshells และดังนั้นการตั้งค่าเหล่านั้นจะติดโดยไม่คำนึงถึงเชลล์พาเรนต์ stty saneไม่จำเป็นว่าคุณต้องการทำอะไร - เป็นการดีกว่าที่จะคืนสภาพให้เป็นวิธีที่คุณพบว่าดีกว่าที่จะถือว่ารัฐอยู่saneในจุดนั้น หากฉันไม่ได้กู้คืนสิ่งเหล่านั้นechoจะอยู่ทั่วทุกที่ การหาสาเหตุนั้นเป็นสาเหตุที่ฉันมาช้า - คำตอบของคุณไม่ได้อยู่ที่นี่เมื่อฉันเริ่มทำการทดสอบ
mikeserv
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.