Benzer bir şey görmedim ve burada tüm özel işlevler tek başına renderlamaya odaklanıyor gibi görünüyor ... bu yüzden aşağıdaki basit adımlarla POSIX uyumlu çözümüm adım adım açıklamalarla çünkü bu soru önemsiz değil.
TL; DR
İlerleme çubuğunun oluşturulması çok kolaydır. Ne kadarının oluşturulması gerektiğini tahmin etmek farklı bir konudur. İlerleme çubuğunu şu şekilde oluşturur (canlandırır) - bu örneği bir dosyaya kopyalayıp yapıştırabilir ve çalıştırabilirsiniz:
#!/bin/sh
BAR='####################' # this is full bar, e.g. 20 chars
for i in {1..20}; do
echo -ne "\r${BAR:0:$i}" # print $i chars of $BAR from 0 position
sleep .1 # wait 100ms between "frames"
done
{1..20}
- 1'den 20'ye kadar olan değerler
echo -n
- sonunda yeni satır olmadan yazdır
echo -e
- yazdırma sırasında özel karakterleri yorumlama
"\r"
- satır başı, satırın başına dönmek için özel bir karakter
Herhangi bir içeriği herhangi bir hızda oluşturmasını sağlayabilirsiniz, bu nedenle bu yöntem çok evrenseldir, örneğin genellikle saçma filmlerde "hack'lerin" görselleştirilmesi için kullanılır, şaka yapmaz.
Tam cevap
Sorunun eti, $i
değerin nasıl belirleneceği , yani ilerleme çubuğunun ne kadarının görüntüleneceğidir. Yukarıdaki örnekte for
, prensibi göstermek için döngüde artmasına izin verdim , ancak gerçek bir yaşam uygulaması sonsuz bir döngü kullanacak ve $i
her yinelemede değişkeni hesaplayacaktır . Bahsedilen hesaplamayı yapmak için aşağıdaki bileşenlere ihtiyaç vardır:
- ne kadar iş yapılmalı
- şu ana kadar ne kadar iş yapıldı
cp
Bir kaynak dosyanın ve hedef dosyanın boyutuna ihtiyaç duyması halinde :
#!/bin/sh
$src=/path/to/source/file
$tgt=/path/to/target/file
cp "$src" "$tgt" & # the & forks the `cp` process so the rest
# of the code runs without waiting (async)
BAR='####################'
src_size=$(stat -c%s "$src") # how much there is to do
while true; do
tgt_size=$(stat -c%s "$tgt") # how much has been done so far
i=$(( $tgt_size * 20 / $src_size ))
echo -ne "\r${BAR:0:$i}"
if [ $tgt_size == $src_size ]; then
echo "" # add a new line at the end
break; # break the loop
fi
sleep .1
done
stat
- dosya istatistiklerini kontrol edin
-c
- biçimlendirilmiş değeri döndür
%s
- toplam boyut
Dosya açma gibi işlemler durumunda, kaynak boyutunu hesaplamak biraz daha zordur ancak sıkıştırılmamış bir dosyanın boyutunu almak kadar kolaydır:
#!/bin/sh
src_size=$(gzip -l "$src" | tail -n1 | tr -s ' ' | cut -d' ' -f3)
gzip -l
- zip arşivi hakkında bilgi görüntüleme
tail -n1
- alttan 1 çizgi ile çalışma
tr -s ' '
- birden çok boşluğu bir dile çevirin (sıkıştırın)
cut -d' ' -f3
- 3. boşlukla ayrılmış sütunu kesin
İşte sorunun etini. Bu çözüm gittikçe daha az geneldir. Gerçek ilerlemenin tüm hesaplamaları, görselleştirmeye çalıştığınız alana sıkı sıkıya bağlıdır, tek bir dosya işlemi, bir zamanlayıcı geri sayımı, bir dizindeki dosya sayısının artması, birden çok dosyada işlem vb. tekrar kullanılamaz. Tek kullanımlık kısım ilerleme çubuğu oluşturma işlemidir. Yeniden kullanmak için onu soyutlamanız ve bir dosyaya kaydetmeniz (örn. /usr/lib/progress_bar.sh
), Ardından alanınıza özgü giriş değerlerini hesaplayan işlevleri tanımlamanız gerekir. Genelleştirilmiş bir kod şöyle görünebilirdi (aynı zamanda $BAR
dinamiği de yaptım çünkü insanlar bunu istiyordu, gerisi şimdiye kadar net olmalı):
#!/bin/sh
BAR_length=50
BAR_character='#'
BAR=$(printf "%${BAR_length}s" | tr ' ' $BAR_character)
work_todo=$(get_work_todo) # how much there is to do
while true; do
work_done=$(get_work_done) # how much has been done so far
i=$(( $work_done * $BAR_length / $work_todo ))
echo -ne "\r${BAR:0:$i}"
if [ $work_done == $work_todo ]; then
echo ""
break;
fi
sleep .1
done
printf
- belirli bir biçimde bir şeyler basmak için yerleşik
printf '%50s'
- hiçbir şey yazdırmayın, 50 boşlukla doldurun
tr ' ' '#'
- her alanı karma işaretine çevir
Ve işte böyle kullanacaksınız:
#!/bin/sh
src=/path/to/source/file
tgt=/path/to/target/file
function get_work_todo() {
echo $(stat -c%s "$src")
}
function get_work_done() {
[ -e "$tgt" ] && # if target file exists
echo $(stat -c%s "$tgt") || # echo its size, else
echo 0 # echo zero
}
cp "$src" "$tgt" & # copy in the background
source /usr/lib/progress_bar.sh # execute the progress bar
Açıkçası, bir fonksiyona sarılabilir, borulu akışlarla çalışmak için yeniden yazılabilir, zehiriniz ne olursa olsun, başka bir dile yeniden yazılabilir.