Bash'i eklemek yerine önceki çıktının üzerine yaz


22

Bir bash zamanlayıcısı için bu kodu kullanıyorum:

#!/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!"

Bu bana böyle bir şey verir

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

Çıktının büyük bir iz oluşturmaması için saniyenin son değerini en son ile değiştirme olasılığı var mıdır, ancak saniye tek bir noktada gerçek bir zaman gibi geri sayım yapar mı? (Ne demek istediğimi anlıyorsundur :))


Bunu watchkomutla yapmanın bir yolu olabilir , ancak tam olarak nasıl yapacağımdan emin değilim.
AJMansfield 24:13

Yanıtlar:


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
Şaşırtıcı, çok teşekkürler. Diğer okuyucular için sadece bir bildirim. Yukarıdaki koda uyması için boşluk nedeniyle "\ b \ b \ b" echo -en kullanmanız gerekir.
NES

1
+1 Güzel, ama ... 10'un altında mesajı yemeye başladı ...
lepe

1
Evet, kullanımı daha iyi \r. Cevabımı gör.
Mikel

3
Bash kılavuzunda Gönderen: The old format $[expression] is deprecated and will be removed in upcoming versions of bash.. Bunun yerine POSIX $((expression))veya- ((komutunu kullanın. Örneğin sek=$(( sek - 1 ))veya (( sek = sek - 1 ))veya (( sek-- )).
geirha

17

Temel olarak anehehep’in cevabıyla aynıdır, fakat \rBackspace ( \b) yerine Return ( ) işlevini kullanır, çünkü uzunluğun daima aynı olup olmayacağını bilmiyoruz, örneğin ne zaman $sek < 10.

Ayrıca, ilk echokullanmalısınız $sekdeğil sabit kod 60.

Son olarak, sonraki boşluğa dikkat edin ....

#!/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

Bash ile özel değişkeni kullanabilirsiniz SECONDS.

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

+1 İyi cevap, ayrıca SECONDS hakkında hiçbir şey bilmiyordum.
Mikel

Çalışır, ancak test edilmiş bir loop-koşulu durumu olarak 'uyku .5'i görmek biraz gariptir. Howerver Ben özellikle $ SECONDS kullanımını seviyorum, çünkü gerçek zamanla (yani, aralarında sabit bir zaman değil) uykuda olduğu gibi zaman alıcı işlemler 1) ... SECONDS Bu değişken, kabuğun başlatılmasından bu yana geçen saniye sayısına genişler. (bu yüzden muhtemelen 0'a ayarlamazdım ... sadece senaryo başladığında 60 saniye daha test et) .. +1
Peter.O

Daha fazla yorum yapıyorum, çünkü sadece doğru bir bilgi almak için şahsen ilgileniyorum çünkü $ SECONDS'i test ettim ve '0' olarak ayarlanmış olup olmadığına hala bağlı sistemin mevcut kesirli saniye .. yani. Bunu '0' olarak ayarlamak 0.99'luk bir zamanla sonuçlanabilir ... (olduğu gibi bırakılırsa aynıdır) .... Yani, en iyi ortalama şans, saniyenin sadece 5'i içinde olmaktır. .. Sadece bir yorum (bu ne için yorumlar :)
Peter.O

@ fred.bear Pekala, asla tam olarak doğru olamayacaksınız; diğer bazı işlemler geri sayım devam ederken CPU ve / veya IO'yu beklemeye başlayabilir ve daha önce sahip olduğunuz doğruluğu mahvedebilir. Yapabileceğin şey, en az X zaman beklemesini sağlamak ve istenirse kaba bir geri sayım vermek. Bir program “bir dakika sürecek” dediğinde, milisaniyeye 1 dakika kadar sürmesini bekler misiniz? veya 1 dakikanızı almak için
geirha

@geirha ... Evet, bu çeşitlilik vakaların% 99'unda önemli olmayacak ve benim için harika bir değer ... SECONDS olduğunu fark ettin ... Sadece sınırlarını buluyorum ... betiğinizin, .01 sn'lik bir uykuya dayanan bitirme zamanını rapor eden (artı, sizin de belirttiğiniz gibi, herhangi bir harici sistem gecikmesi) sadece bir saniye tıklandığında basılabildiğini, ancak daha sonra ilk 'saniyenin' çok yakında basıldığını keşfettim. (bir durumda, sadece ilk 01 saniye sonra) .. Hepsi bash öğrenme eğrimin bir parçası ... Cevabını beğendim, bu yüzden ona daha derin bir göz attım.
Peter.O

3

Buna ek olarak \rveya \byaklaşırken, terminale tüm çizgiyi temizlemesini söyleyen \033[2K kontrol karakterini kullanmak mümkündür . Bunun avantajı, silmek istediğiniz karakter \bsayısıyla eşleşmek zorunda olmamanız ve yeni satır eskiden daha kısaysa ekranda çıkacak karakterlerin olmamasıdır. bir.\b\r

Aşağıda, bu soruya nasıl uygulanabileceğinin bir örneği verilmiştir ve işte bu, önyükleme iletilerine benzer bir çıktı oluşturmak için ilgili uygulamanın bir örneğidir. Bu özel örnekte, zamanlayıcı 0 saniyeye ulaşıldığında gider ve zamanlayıcı çizgisi "Hazır!" İle değiştirilir ifade.

#!/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!"

Diğer bir alternatif dialog, komut satırında basit diyaloglar oluşturmak için komut kullanmak olacaktır . İletişim kutusu zamanlayıcı süresince ekranda kalır ve döngüle birlikte güncellenir ve bittiği zaman - zamanlayıcı sorunsuz bir şekilde "Hazır! Çıkmak için basın" mesajı ile değiştirilir:

#!/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

dialogmac üzerinde mevcut değil: /
Ricky Levi

1

İşte burada okuduktan ve biraz daha fazlasını okuduktan sonra ortaya çıkan şey:

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

Daha okunabilir:

#!/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, hangi pozitif tamsayıya ayarlıysa ve printf uygun dolgu ile ilgilenir. Ubuntu ve cygwin altında test edilmiştir.


1

Taşıma iadesi yaparak bunu başarabilir \r.

Tek bir kod satırında echo -ne

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

veya ile printf

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

-2

Geri sayım saati:

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

ve 'normal' kronometre:

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

durmak için kontrol + c


Bu, metnin üzerine yazma hakkındaki soruyu cevaplamıyor
Jeremy Kerr
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.