เขียนทับเอาต์พุตก่อนหน้าใน Bash แทนการต่อท้าย


22

สำหรับตัวจับเวลาทุบตีฉันใช้รหัสนี้:

#!/bin/bash
sek=60
echo "60 Seconds Wait!"
echo -n "One Moment please "
while [ $sek -ge 1 ]
do
   echo -n "$sek "  
sleep 1
   sek=$[$sek-1]
done
echo
echo "ready!"

นั่นทำให้ฉันเป็นอย่างนั้น

One Moment please: 60 59 58 57 56 55 ...

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


อาจมีวิธีในการทำเช่นนี้กับwatchคำสั่งถึงแม้ว่าฉันไม่แน่ใจว่าจะทำอย่างไร
AJMansfield

คำตอบ:


14
#!/bin/bash
sek=60
echo "60 Seconds Wait!"
echo -n "One Moment please "
while [ $sek -ge 1 ]
do
   echo -n "$sek" 

sleep 1
   sek=$[$sek-1]
   echo -en "\b\b"
done
echo
echo "ready!"

2
น่าทึ่งขอบคุณมาก เพียงหนึ่งประกาศสำหรับผู้อ่านอื่น ๆ เพื่อให้พอดีกับรหัสข้างต้นคุณต้องใช้ echo -en "\ b \ b \ b" เนื่องจากมีที่ว่าง
NES

1
+1 ดี แต่ ... ต่ำกว่า 10 ก็จะเริ่มกินข้อความ ...
Lepe

1
\rอ๋อดีกว่าการใช้ ดูคำตอบของฉัน
Mikel

3
The old format $[expression] is deprecated and will be removed in upcoming versions of bash.จากคู่มือการทุบตีของ: ใช้ POSIX $((expression))หรือ((-command แทน เช่นsek=$(( sek - 1 ))หรือหรือ(( sek = sek - 1 )) (( sek-- ))
geirha

17

โดยพื้นฐานแล้วเหมือนกับคำตอบของ aneeshep แต่ใช้ Return ( \r) มากกว่า Backspace ( \b) เพราะเราไม่ทราบว่าความยาวจะเหมือนกันเสมอเช่นเมื่อ$sek < 10ใด

นอกจากนี้ครั้งแรกของคุณechoควรใช้ไม่ยากรหัส$sek60

...สุดท้ายทราบพื้นที่หลังจากที่

#!/bin/bash
sek=60
echo "$sek Seconds Wait!"
while [ $sek -ge 1 ]
do
   echo -ne "One Moment please $sek ... \r"
   sleep 1
   sek=$[$sek-1]
done
echo
echo "ready!"

7

SECONDSด้วยการทุบตีคุณสามารถใช้ตัวแปรพิเศษ

#BASH
SECONDS=0;
while sleep .5 && ((SECONDS <= 60)); do 
    printf '\r%s: %2d' "One moment please" "$((60-SECONDS))"
done
printf '\n'

+1 คำตอบที่ดีแถมฉันไม่เคยรู้เรื่องวินาทีเลย
มิเคล

มันใช้งานได้ แต่มันค่อนข้างแปลกที่ได้เห็น 'sleep .5' เป็นเงื่อนไข while-loop ที่ผ่านการทดสอบ .. Howerver ฉันชอบใช้ $ SECONDS เป็นพิเศษเพราะเกี่ยวข้องกับเวลาจริง (เช่นไม่ใช่เวลาที่ผ่านไปคงที่ระหว่าง การกระทำที่ใช้เวลานานเช่นเดียวกับการนอนหลับ 1) ... SECONDS ตัวแปรนี้ขยายเป็นจำนวนวินาทีตั้งแต่เชลล์เริ่มทำงาน (ดังนั้นฉันอาจจะไม่ตั้งค่าเป็น 0 .. เพียงแค่ทดสอบเป็นเวลา 60 วินาทีเพิ่มเติมจากเมื่อสคริปต์เริ่ม) .. +1
Peter.O

ฉันกำลังแสดงความคิดเห็นเพิ่มเติมเพียงเพราะฉันสนใจส่วนตัวในวิธีที่จะได้รับ coutntdown ที่ถูกต้อง ... ฉันได้ทดสอบ $ SECONDS และดูเหมือนว่าไม่ว่าจะถูกตั้งค่าเป็น '0' หรือไม่ก็ขึ้นอยู่กับ ส่วนที่สองของระบบในปัจจุบัน .. การตั้งค่าเป็น '0' อาจส่งผลให้เวลา 0.99 ... (เช่นเดียวกันถ้ามันเป็นไปตามที่เป็นอยู่) .... ดังนั้นโอกาสเฉลี่ยที่ดีที่สุดคืออยู่ภายใน 0.5 วินาทีเท่านั้น .. เพียงแค่ความคิดเห็น (นั่นคือสิ่งที่แสดงความคิดเห็นสำหรับ :)
Peter.O

@ fred.bear ดีคุณจะไม่ได้รับความถูกต้องจริง ๆ ; กระบวนการบางอย่างอาจเริ่มต้นการ hogging CPU และ / หรือ IO ในขณะที่การนับถอยหลังกำลังดำเนินไปและทำลายความแม่นยำที่คุณมีก่อนหน้านี้ สิ่งที่คุณสามารถทำได้คือให้รออย่างน้อยสิบเท่าของเวลาและให้การนับคร่าวๆหากต้องการ เมื่อโปรแกรมแจ้งว่า "จะใช้เวลาหนึ่งนาที" คุณคาดหวังให้ใช้เวลา 1 นาทีถึงมิลลิวินาทีหรือไม่ หรือจะใช้เวลา 1 นาทีให้หรือไม่กี่วินาที?
geirha

@geirha ... ใช่รูปแบบนั้นไม่สำคัญใน 99% ของกรณีและความยิ่งใหญ่ที่คุณทำให้ฉันได้รับทราบถึง $ SECONDS ... ฉันแค่หาข้อ จำกัด ... ฉันเล่นกับ รูปแบบของสคริปต์ของคุณซึ่งรายงานเวลาสิ้นสุดโดยใช้. 01 วินาทีโหมดสลีป (บวกตามที่คุณกล่าวถึงความล่าช้าของระบบภายนอก) แต่ก็พิมพ์เฉพาะเมื่อมีการคลิกครั้งที่สอง แต่ฉันพบว่า 'วินาที' แรกกำลังพิมพ์เร็วเกินไป (ในกรณีเดียวหลังจากผ่านครั้งแรกที่. 01 วินาที) .. มันเป็นส่วนหนึ่งของการเรียนรู้ทุบตีของฉันทั้งหมด ... ฉันชอบคำตอบของคุณนั่นคือสาเหตุที่ฉันมองลึกลงไป
Peter.O

3

นอกจาก\rหรือ\bวิธีการแล้วยังมีความเป็นไปได้ที่จะใช้\033[2K ตัวควบคุมซึ่งบอกให้เทอร์มินัลทำการล้างทั้งบรรทัด ข้อดีของการเปรียบเทียบนี้\bคือคุณไม่จำเป็นต้องจับคู่\bกับจำนวนอักขระที่คุณต้องการลบและเมื่อเปรียบเทียบกับ\rจะไม่มีอักขระโผล่ออกมาบนหน้าจอหากบรรทัดใหม่สั้นกว่าเก่า หนึ่ง.

ด้านล่างนี้เป็นตัวอย่างของวิธีการใช้กับคำถามนี้และนี่คือตัวอย่างของแอปพลิเคชันที่เกี่ยวข้องเพื่อสร้างผลลัพธ์ที่คล้ายกับข้อความบูต ในตัวอย่างนี้ตัวจับเวลาจะหายไปเมื่อถึงวินาทีที่ 0 และเส้นจับเวลาจะถูกแทนที่ด้วย "Ready!" วลี.

#!/bin/bash
sek=60
echo "60 Seconds"

while ((sek--)); do
    printf "One moment please: %d" "$sek"
    sleep 1
    printf "\r%b" "\033[2K"
done
echo "Ready!"

อีกทางเลือกหนึ่งคือใช้dialogคำสั่งสำหรับสร้างไดอะล็อกอย่างง่ายใน command-line กล่องโต้ตอบจะยังคงอยู่บนหน้าจอในช่วงระยะเวลาของตัวจับเวลาและอัปเดตด้วยลูปและตามเวลาที่ทำ - ตัวจับเวลาจะถูกแทนที่ด้วยข้อความ "พร้อม! กดเพื่อออก" ในลักษณะที่ราบรื่น:

#!/bin/bash
sek=60
echo "60 Seconds"

while ((sek--)); do
    echo "$sek" | dialog --progressbox "Please wait" 10 25
    sleep 1
done
dialog --msgbox "Ready! Press <OK> to finish" 10 25

dialogไม่มีอยู่ใน mac: /
Ricky Levi

1

นี่คือสิ่งที่ฉันเกิดขึ้นหลังจากอ่านที่นี่และอีกหนึ่งซับ:

SEC=101;for i in `seq $SEC -1 1`;do printf "\rNext in: %`expr length $SEC`ds" "$i";sleep 1;done;echo

สามารถอ่านเพิ่มเติมได้ที่:

#!/bin/bash
SEC=101

for i in `seq $SEC -1 1`;do
        printf "\rNext in: %`expr length $SEC`ds" "$i";
        sleep 1;
done
echo

ตำแหน่งที่ SEC สามารถตั้งค่าให้เป็นจำนวนเต็มบวกใด ๆ และ printf จะดูแลการเติมที่เหมาะสม ทดสอบภายใต้ Ubuntu และ cygwin


1

สามารถทำได้โดยการวางสายการบินคืน \rจะประสบความสำเร็จโดยการวางกลับสายการบิน

ในรหัสบรรทัดเดียวก็เป็นไปได้ด้วย echo -ne

for i in {60..1}; do echo -ne "One moment please: $i\r" && sleep 1; done

หรือกับ printf

for i in {60..1}; do printf "One moment please: $i\r" && sleep 1; done

-2

จับเวลาถอยหลัง:

MIN=1 && for i in $(seq $(($MIN*60)) -1 1); do echo -n "$i, "; sleep 1; done; echo -e "nnMessage"

และนาฬิกาจับเวลา 'ปกติ' คือ:

START=$( date +%s ); while true; do CURRENT=$( date +%s ) ; echo $(( CURRENT-START )) ; sleep 1 ; echo -n  ; done

control + c เพื่อหยุด


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