Kabuk betiğine bir ilerleme çubuğu nasıl eklenir?


413

* NIX'te bash veya başka bir kabukta komut dosyası yazarken, birkaç saniyeden uzun sürecek bir komut çalıştırırken, bir ilerleme çubuğu gereklidir.

Örneğin, büyük bir dosyayı kopyalayarak, büyük bir katran dosyasını açarak.

Kabuk komut dosyalarına ilerleme çubukları eklemeyi nasıl önerirsiniz?


Ayrıca kontrol mantığının örnekleri için stackoverflow.com/questions/12498304/… adresine bakın (bir işi arka planlayın ve bitene kadar bir şeyler yapın).
tripleee

1
Komut dosyası oluştururken sıklıkla yararlı bulduğumuz bir dizi gereksinim vardır. günlüğe kaydetme, ilerleme, renkler, süslü çıktılar vb. görüntüleme ... Her zaman basit bir betik çerçevesi olması gerektiğini hissettim. Sonunda birini bulamadığım için bir tane uygulamaya karar verdim. Bunu faydalı bulabilirsiniz. Saf bash, yani Sadece Bash. SumithLansakara/JustBash
Sumudu

Yanıtlar:


685

Bir satırın üzerine yazarak bunu uygulayabilirsiniz. Terminale \ryazmadan satırın başına gitmek için kullanın \n.

\nÇizgiyi ilerletmeyi bitirdiğinizde yazın .

Kullanmak echo -neiçin:

  1. yazdırmamak \nve
  2. kaçış dizilerini tanımak gibi \r.

İşte bir demo:

echo -ne '#####                     (33%)\r'
sleep 1
echo -ne '#############             (66%)\r'
sleep 1
echo -ne '#######################   (100%)\r'
echo -ne '\n'

Aşağıdaki bir yorumda, uzun bir satırla başlayıp kısa bir satır yazmak istiyorsanız, puk, bu "başarısız" durumundan bahseder: Bu durumda, uzun satırın uzunluğunun üzerine yazmanız gerekir (örn. Boşluklarla).


23
Göre yankı (MacOS X üzerinde en az) adam sayfası sh / bash kullanmak kendi yerleşik yankı "-n" kabul etmiyor komuta ... yani koymak gerekir aynı şeyi başarmak için \ r dizenin sonunda \ c yerine, sadece \ r
Justin Jenkins

51
Bunun çıkışının taşınabilir yolu printfyerine kullanmaktır echo.
Jens

9
printf için bu biçimi kullanmamız gerekir: printf "#### (50%%)\r"tek tırnak işaretleri ile çalışmaz ve yüzde işaretinin kaçması gerekir.
nurettin

7
Bunu almadım - kabul edildi ve "Bu işlemin bilinmeyen donanımda ne kadar süreceğini tahmin edeceğim" hackleri için yığınlar? pv doğru cevap IMO (ancak çubuk da yapacak)
Stephen

19
Soru, dosya kopyalama örneğiyle "İlerleme çubuklarını nasıl yaparım" idi. Ben bir dosya kopyalama işlemi boyunca ne kadar hesaplama değil, "grafik" sorunu üzerinde duruldu.
Mitch Haile

73

Ayrıca , bir döndürücünün nasıl yapılacağıyla da ilgilenebilirsiniz :

Bash'de bir spinner yapabilir miyim?

Elbette!

i=1
sp="/-\|"
echo -n ' '
while true
do
    printf "\b${sp:i++%${#sp}:1}"
done

Döngü her tekrarlandığında, sp dizesindeki bir sonraki karakteri görüntüler ve sona ulaştığında onu sarar. (i, görüntülenecek geçerli karakterin konumu ve $ {# sp} sp dizesinin uzunluğudur).

\ B dizesi yerine 'backspace' karakteri konur. Alternatif olarak, satırın başına dönmek için \ r ile oynayabilirsiniz.

Yavaşlamasını istiyorsanız, döngünün içine bir uyku komutu koyun (printf'den sonra).

POSIX eşdeğeri şöyle olur:

sp='/-\|'
printf ' '
while true; do
    printf '\b%.1s' "$sp"
    sp=${sp#?}${sp%???}
done

Çok fazla iş yapan bir döngünüz varsa, dönücüyü güncellemek için her yinelemenin başında aşağıdaki işlevi çağırabilirsiniz:

sp="/-\|"
sc=0
spin() {
   printf "\b${sp:sc++:1}"
   ((sc==${#sp})) && sc=0
}
endspin() {
   printf "\r%s\n" "$@"
}

until work_done; do
   spin
   some_work ...
done
endspin

15
Çok daha kısa versiyon, tamamen taşınabilir *: while :;do for s in / - \\ \|; do printf "\r$s";sleep .1;done;done(*: sleepondalık yerine ints gerektirebilir)
Adam Katz

1
@Daenyth. Teşekkürler. Lütfen önceki kodu kullanarak ilerleme olduğunu izlemek için gereken komutu çağırmalıyız?
goro

@goro: some_work ...Yukarıdaki satırda; bu yararlı cevabı temel alan daha ayrıntılı bir tartışma ve Adam Katz'in POSIX uyumuna odaklanan yararlı yorumu burada bulunabilir .
mklement0

@AdamKatz: Bu yararlı, taşınabilir bir sadeleştirme, ancak Daenyth'in yaklaşımını eşleştirmek için iplikçinin , aksi takdirde sadece bir satırın en başında çalışacağından \bziyade temel alması gerekir \r: while :; do for c in / - \\ \|; do printf '%s\b' "$c"; sleep 1; done; done- veya imlecin arkasında durması durumunda istenmeyen:printf ' ' && while :; do for c in / - \\ \|; do printf '\b%s' "$c"; sleep 1; done; done
mklement0

1
@kaushal - Ctrl + C manuel olarak durduracaktır. Arkaplanlı bir işiniz varsa, PID'sini ( job=$!) saklayabilir ve sonra çalıştırabilirsiniz while kill -0 $job 2>/dev/null;do …, örneğin:sleep 15 & job=$!; while kill -0 $job 2>/dev/null; do for s in / - \\ \|; do printf "\r$s"; sleep .1; done; done
Adam Katz

48

Bazı yayınlar komutun ilerlemesinin nasıl görüntüleneceğini göstermiştir. Hesaplamak için ne kadar ilerlediğinizi görmeniz gerekir. BSD sistemlerinde dd (1) gibi bazı komutlar bir SIGINFOsinyali kabul eder ve ilerlemelerini rapor eder. Linux sistemlerinde bazı komutlar benzer şekilde yanıt verecektir SIGUSR1. Bu özellik mevcutsa, ddişlenen bayt sayısını izlemek için girişinizi yönlendirebilirsiniz .

Alternatif olarak, lsofdosyanın okuma işaretçisinin ofsetini elde etmek ve böylece ilerlemeyi hesaplamak için kullanabilirsiniz. Belirtilen bir işlemi veya dosyayı işleme sürecini gösteren pmonitor adlı bir komut yazdım . Bununla birlikte aşağıdakiler gibi şeyler yapabilirsiniz.

$ pmonitor -c gzip
/home/dds/data/mysql-2015-04-01.sql.gz 58.06%

Blogumda Linux ve FreeBSD kabuk komut dosyalarının önceki bir sürümü görünüyor .


Bu harika, ben her zaman pv yoluyla bir şeyler boru unutmak :-) Ben "stat" komutu biraz farklı çalışır, bu betiğin (Linux) sürümü düşünüyorum: gist.github.com/unhammer/b0ab6a6aa8e1eeaf236b
unhammer

Harika gönderi, awkoyuna girdiğinde her zaman sev !
ShellFish

Bu harika! Harika senaryo için teşekkürler!
thebeagle

47

Geçen gün yazdığım kolay bir ilerleme çubuğu işlevi var:

#!/bin/bash
# 1. Create ProgressBar function
# 1.1 Input is currentState($1) and totalState($2)
function ProgressBar {
# Process data
    let _progress=(${1}*100/${2}*100)/100
    let _done=(${_progress}*4)/10
    let _left=40-$_done
# Build progressbar string lengths
    _fill=$(printf "%${_done}s")
    _empty=$(printf "%${_left}s")

# 1.2 Build progressbar strings and print the ProgressBar line
# 1.2.1 Output example:                           
# 1.2.1.1 Progress : [########################################] 100%
printf "\rProgress : [${_fill// /#}${_empty// /-}] ${_progress}%%"

}

# Variables
_start=1

# This accounts as the "totalState" variable for the ProgressBar function
_end=100

# Proof of concept
for number in $(seq ${_start} ${_end})
do
    sleep 0.1
    ProgressBar ${number} ${_end}
done
printf '\nFinished!\n'

Veya https://github.com/fearside/ProgressBar/ adresinden çekin


1.2.1.1 altındaki satırı açıklayabilir misiniz? _Fill ve _empty değişkenleriyle sed ikamesi mi yapıyorsunuz? Kafam karıştı.
Chirag

Sed kullanmak yerine, bash dahili "Substring Değiştirme" kullanarak im, bu kolay bir iş olduğundan, bu tür işler için bash'ın dahili işlevlerini kullanmayı tercih ederim. Kod da daha güzel görünüyor. :-) tldp.org/LDP/abs/html/string-manipulation.html adresini ziyaret edin ve alt dize değiştirme işlemini arayın.
fearside

ve $ {_ fill} $ {_ done} boşluk sayısı olarak atanır. Bu güzel. İyi iş adamı. Kesinlikle tüm bash komut dosyalarında kullanacağım haha
Chirag

Harika bir iş @fearside! _Progress son değerden değişmediğinde, hızı artırmak için atlamak için küçük bir değişiklik yaptım. github.com/enobufs/bash-tools/blob/master/bin/progbar
enobufs

Tatlı. printf "\rProgress : [${_fill// /▇}${_empty// / }] ${_progress}%%"
Çizgiyi

44

linux pv komutunu kullanın:

http://linux.die.net/man/1/pv

Akışın ortasındaysa boyutu bilmiyor, ancak bir hız ve toplam veriyor ve oradan ne kadar sürmesi gerektiğini ve ne kadar geri bildirim alacağını anlayabiliyorsunuz, böylece asılı olmadığını biliyorsunuz.


32

Seçilen cevaptan daha seksi bir şey arıyordum, kendi senaryom da öyle.

Ön izleme

progress-bar.sh iş başında

Kaynak

Github üzerine koydumprogress-bar.sh

progress-bar() {
  local duration=${1}


    already_done() { for ((done=0; done<$elapsed; done++)); do printf "▇"; done }
    remaining() { for ((remain=$elapsed; remain<$duration; remain++)); do printf " "; done }
    percentage() { printf "| %s%%" $(( (($elapsed)*100)/($duration)*100/100 )); }
    clean_line() { printf "\r"; }

  for (( elapsed=1; elapsed<=$duration; elapsed++ )); do
      already_done; remaining; percentage
      sleep 1
      clean_line
  done
  clean_line
}

kullanım

 progress-bar 100

1
Bunun, işlemin uzunluğunun bilinmediği bir işleme nasıl entegre edildiğini anlamıyorum. İşlemim daha önce tamamlandıysa, örneğin bir dosyayı açmak için ilerleme çubuğu nasıl durdurulur.
Ocak

Bence kullanımı olmalıprogress-bar 100
jirarium

Gerçekten de çekici ilerleme. Uzak sunucularda ssh üzerinden uzun süre işlem yapan bir işleve nasıl bağlanabilir? Yani uzak sunuculardaki bir yükseltme zamanlamasını (örneğin) nasıl ölçmek mümkün?
yüzsüz

1
@faceless zaman sağlamak bu kod kapsamında değildir ve geri sayım
Édouard Lopez

1
@ Fusion, modern kabuk için güvenli olması gereken unicode bir karakterdir (U + 2587 DÜŞÜK YEDİ EKSİK BLOK). Envilerinizi deneyin
Édouard Lopez

18

GNU tar basit bir ilerleme çubuğunun işlevselliğini sağlayan kullanışlı bir seçeneğe sahiptir.

(...) Kullanılabilir başka bir denetim noktası eylemi 'nokta' (veya '.'). Katran'a standart listeleme akışında tek bir nokta basması talimatını verir, örneğin:

$ tar -c --checkpoint=1000 --checkpoint-action=dot /var
...

Aynı etki şu yollarla elde edilebilir:

$ tar -c --checkpoint=.1000 /var

En basit yaklaşım için +1! Yazdırılan nokta görmüyorsanız, örneğin sayıyı azaltmayı deneyin --checkpoint=.10. Ayıklandığında da harika çalışıyor tar -xz.
Noam Manos

13

Pipeview (pv) yardımcı programını kullanarak sistemimde çalışan daha basit bir yöntem.

srcdir=$1
outfile=$2


tar -Ocf - $srcdir | pv -i 1 -w 50 -berps `du -bs $srcdir | awk '{print $1}'` | 7za a -si $outfile

13

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, $ideğ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 $iher yinelemede değişkeni hesaplayacaktır . Bahsedilen hesaplamayı yapmak için aşağıdaki bileşenlere ihtiyaç vardır:

  1. ne kadar iş yapılmalı
  2. şu ana kadar ne kadar iş yapıldı

cpBir 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 $BARdinamiğ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.


1
En basit şeyleri isteyenler için, ben sadece cprn ilk cevapla benimkini yaptım. Çubuğu çizmek için bazı aptal orantılılık kuralını kullanan bir işlevde çok basit bir ilerleme çubuğu: pastebin.com/9imhRLYX
YCN-


9

APT stili ilerleme çubuğu (Normal çıktıyı bozmaz)

resim açıklamasını buraya girin

EDIT: Güncellenmiş bir sürüm için github sayfamı kontrol et

Bu sorunun cevabından memnun kalmadım. Şahsen aradığım APT tarafından görüldüğü gibi süslü bir ilerleme çubuğu oldu.

APT için C kaynak koduna baktım ve bash için kendi eşdeğerimi yazmaya karar verdim.

Bu ilerleme çubuğu terminalin altında iyi duracak ve terminale gönderilen herhangi bir çıkışı engellemeyecektir.

Çubuğun şu anda 100 karakter genişliğinde sabitlendiğini lütfen unutmayın. Terminalin boyutuna göre ölçeklendirmek istiyorsanız, bunu başarmak oldukça kolaydır (github sayfamdaki güncellenmiş sürüm bunu iyi işler).

Senaryomu buraya göndereceğim. Kullanım örneği:

source ./progress_bar.sh
echo "This is some output"
setup_scroll_area
sleep 1
echo "This is some output 2"
draw_progress_bar 10
sleep 1
echo "This is some output 3"
draw_progress_bar 50
sleep 1
echo "This is some output 4"
draw_progress_bar 90
sleep 1
echo "This is some output 5"
destroy_scroll_area

Senaryo (bunun yerine github'daki sürümü şiddetle tavsiye ederim):

#!/bin/bash

# This code was inspired by the open source C code of the APT progress bar
# http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/trusty/apt/trusty/view/head:/apt-pkg/install-progress.cc#L233

#
# Usage:
# Source this script
# setup_scroll_area
# draw_progress_bar 10
# draw_progress_bar 90
# destroy_scroll_area
#


CODE_SAVE_CURSOR="\033[s"
CODE_RESTORE_CURSOR="\033[u"
CODE_CURSOR_IN_SCROLL_AREA="\033[1A"
COLOR_FG="\e[30m"
COLOR_BG="\e[42m"
RESTORE_FG="\e[39m"
RESTORE_BG="\e[49m"

function setup_scroll_area() {
    lines=$(tput lines)
    let lines=$lines-1
    # Scroll down a bit to avoid visual glitch when the screen area shrinks by one row
    echo -en "\n"

    # Save cursor
    echo -en "$CODE_SAVE_CURSOR"
    # Set scroll region (this will place the cursor in the top left)
    echo -en "\033[0;${lines}r"

    # Restore cursor but ensure its inside the scrolling area
    echo -en "$CODE_RESTORE_CURSOR"
    echo -en "$CODE_CURSOR_IN_SCROLL_AREA"

    # Start empty progress bar
    draw_progress_bar 0
}

function destroy_scroll_area() {
    lines=$(tput lines)
    # Save cursor
    echo -en "$CODE_SAVE_CURSOR"
    # Set scroll region (this will place the cursor in the top left)
    echo -en "\033[0;${lines}r"

    # Restore cursor but ensure its inside the scrolling area
    echo -en "$CODE_RESTORE_CURSOR"
    echo -en "$CODE_CURSOR_IN_SCROLL_AREA"

    # We are done so clear the scroll bar
    clear_progress_bar

    # Scroll down a bit to avoid visual glitch when the screen area grows by one row
    echo -en "\n\n"
}

function draw_progress_bar() {
    percentage=$1
    lines=$(tput lines)
    let lines=$lines
    # Save cursor
    echo -en "$CODE_SAVE_CURSOR"

    # Move cursor position to last row
    echo -en "\033[${lines};0f"

    # Clear progress bar
    tput el

    # Draw progress bar
    print_bar_text $percentage

    # Restore cursor position
    echo -en "$CODE_RESTORE_CURSOR"
}

function clear_progress_bar() {
    lines=$(tput lines)
    let lines=$lines
    # Save cursor
    echo -en "$CODE_SAVE_CURSOR"

    # Move cursor position to last row
    echo -en "\033[${lines};0f"

    # clear progress bar
    tput el

    # Restore cursor position
    echo -en "$CODE_RESTORE_CURSOR"
}

function print_bar_text() {
    local percentage=$1

    # Prepare progress bar
    let remainder=100-$percentage
    progress_bar=$(echo -ne "["; echo -en "${COLOR_FG}${COLOR_BG}"; printf_new "#" $percentage; echo -en "${RESTORE_FG}${RESTORE_BG}"; printf_new "." $remainder; echo -ne "]");

    # Print progress bar
    if [ $1 -gt 99 ]
    then
        echo -ne "${progress_bar}"
    else
        echo -ne "${progress_bar}"
    fi
}

printf_new() {
    str=$1
    num=$2
    v=$(printf "%-${num}s" "$str")
    echo -ne "${v// /$str}"
}

7

Bu, bir komutun hala yürütülmekte olduğunu görselleştirmenizi sağlar:

while :;do echo -n .;sleep 1;done &
trap "kill $!" EXIT  #Die with parent if we die prematurely
tar zxf packages.tar.gz; # or any other command here
kill $! && trap " " EXIT #Kill the loop and unset the trap or else the pid might get reassigned and we might end up killing a completely different process

Bu , arka planda çalışan ve bir "." Yankılanan sonsuz while döngüsü oluşturur. her saniye. Bu .kabukta görüntülenir. tarKomutu veya istediğiniz herhangi bir komutu çalıştırın . Bu komut yürütmeyi tamamladığında , arka planda çalışan son işi öldürür - bu sonsuz while döngüsüdür .


Yürütme sırasında başka bir iş arka planda başlayıp ilerleme döngüsü yerine potansiyel olarak öldürülemedi mi?
Centimane

Bence bu bir betiğe koyacağınızdır, yani bu betiğin sadece çıkışını yakalar.
Iguananaut

1
Bu komutu seviyorum, dosyalarımda kullanıyorum. Nasıl çalıştığını gerçekten anlamadığım için biraz tedirginim. Birinci ve üçüncü satırları anlamak daha kolaydır, ancak hala emin değilim. Bunun eski bir cevap olduğunu biliyorum, ama programlamada yeni başlayanlara yönelik farklı bir açıklama elde etmenin bir yolu var mı
Felipe

1
Bu SADECE doğru cevap, başkalarının sadece Scripting 101 oyuncak ilerleme çubukları olduğu ve hiçbir şey ifade etmediği ve gerçek, bir kerelik, izlenemeyen (neredeyse TÜM) programlar için kullanmadıklarıdır. Teşekkür ederim.
bekce

@Felipe, while döngüsü bir arka plan işlemidir. $! ilk tuzakta bu arka plan işleminin işlem kimliğini yakalar ve geçerli / üst işlem sona ererse arka plan işleminin de ölmesini ve asılı kalmamasını sağlar. Kill deyimi, uzun komutunuz veya komutlarınız sona erdiğinde arka plan işlemini sonlandırır.
floydn

7

İşte böyle görünebilir

Dosya yükleme

[##################################################] 100% (137921 / 137921 bytes)

Bir işin tamamlanmasını beklemek

[#########################                         ] 50% (15 / 30 seconds)

Uygulayan basit fonksiyon

Sadece betiğinize kopyalayıp yapıştırabilirsiniz. Çalışmak için başka bir şey gerektirmez.

PROGRESS_BAR_WIDTH=50  # progress bar length in characters

draw_progress_bar() {
  # Arguments: current value, max value, unit of measurement (optional)
  local __value=$1
  local __max=$2
  local __unit=${3:-""}  # if unit is not supplied, do not display it

  # Calculate percentage
  if (( $__max < 1 )); then __max=1; fi  # anti zero division protection
  local __percentage=$(( 100 - ($__max*100 - $__value*100) / $__max ))

  # Rescale the bar according to the progress bar width
  local __num_bar=$(( $__percentage * $PROGRESS_BAR_WIDTH / 100 ))

  # Draw progress bar
  printf "["
  for b in $(seq 1 $__num_bar); do printf "#"; done
  for s in $(seq 1 $(( $PROGRESS_BAR_WIDTH - $__num_bar ))); do printf " "; done
  printf "] $__percentage%% ($__value / $__max $__unit)\r"
}

Kullanım örneği

Burada, bir dosya yükler ve her yinelemede ilerleme çubuğunu yeniden çizeriz. 2 değer alabildiğimiz sürece gerçekte hangi işin gerçekleştirildiği önemli değildir: maksimum değer ve mevcut değer.

Aşağıdaki örnekte, maksimum değer bir değerdir file_sizeve mevcut değer bir işlev tarafından sağlanır ve çağrılır uploaded_bytes.

# Uploading a file
file_size=137921

while true; do
  # Get current value of uploaded bytes
  uploaded_bytes=$(some_function_that_reports_progress)

  # Draw a progress bar
  draw_progress_bar $uploaded_bytes $file_size "bytes"

  # Check if we reached 100%
  if [ $uploaded_bytes == $file_size ]; then break; fi
  sleep 1  # Wait before redrawing
done
# Go to the newline at the end of upload
printf "\n"

Düzgün ve basit fonksiyon. Çok teşekkürler!
Andreas Kraft

Aradığım şey bu! Çok teşekkürler :)
wajdi_jurry

4

Çoğu unix komutu size bunu yapabileceğiniz bir tür doğrudan geri bildirim vermez. Bazıları kullanabileceğiniz stdout veya stderr çıktısı verecektir.

Tar gibi bir şey için -v anahtarını kullanabilir ve çıktıyı okuduğu her satır için küçük bir animasyon güncelleyen bir programa bağlayabilirsiniz. Tar, dosyaların bir listesini yazarken, program animasyonu güncelleyebilir. Tamamlanma yüzdesini yapmak için dosya sayısını bilmeniz ve satırları saymanız gerekir.

cp bildiğim kadarıyla bu tür bir çıktı vermiyor. Cp'nin ilerlemesini izlemek için kaynak ve hedef dosyaları izlemeniz ve hedefin boyutunu izlemeniz gerekir. Dosya boyutunu almak için stat (2) sistem çağrısını kullanarak küçük bir c programı yazabilirsiniz . Bu, kaynağın boyutunu okur ve hedef dosyayı yoklar ve bugüne kadar yazılan dosyanın boyutuna göre% tamamlanmış bir çubuğu günceller.


4

Benim çözümüm şu anda sıkıştırılmamış ve yazılmakta olan tarball yüzdesini gösteriyor. Bunu 2GB kök dosya sistemi görüntüleri yazarken kullanıyorum. Bu şeyler için gerçekten bir ilerleme çubuğuna ihtiyacınız var. Yaptığım şey, gzip --listtarball'ın toplam sıkıştırılmamış boyutunu elde etmek için kullanmak . Bundan dosyayı 100 parçaya bölmek için gereken engelleme faktörünü hesaplıyorum. Son olarak, her blok için bir kontrol noktası mesajı yazdırıyorum. 2 GB'lık bir dosya için bu yaklaşık 10 MB'lık bir blok verir. Bu çok büyükse, BLOCKING_FACTOR'u 10 veya 100'e bölebilirsiniz, ancak yüzde cinsinden güzel çıktılar yazdırmak daha zordur.

Bash kullandığınızı varsayarsak, aşağıdaki kabuk işlevini kullanabilirsiniz

untar_progress () 
{ 
  TARBALL=$1
  BLOCKING_FACTOR=$(gzip --list ${TARBALL} |
    perl -MPOSIX -ane '$.==2 && print ceil $F[1]/50688')
  tar --blocking-factor=${BLOCKING_FACTOR} --checkpoint=1 \
    --checkpoint-action='ttyout=Wrote %u%  \r' -zxf ${TARBALL}
}

Güzel bir çözüm ama bir dizini sıkıştırmak istediğinizde nasıl yapıyorsunuz?
Samir Sadek

4

Her şeyden önce çubuk sadece bir boru ilerleme ölçer değildir. Diğeri (belki daha da bilinen) pv'dir (boru görüntüleyici).

İkinci olarak, bar ve pv örneğin şu şekilde kullanılabilir:

$ bar file1 | wc -l 
$ pv file1 | wc -l

ya da:

$ tail -n 100 file1 | bar | wc -l
$ tail -n 100 file1 | pv | wc -l

Örneğin, file1 dosya2 dosyası gibi argümanlarda verilen dosyalarla çalışan komutlarda bar ve pv'yi kullanmak istiyorsanız kullanışlı bir hile, işlem ikamesi kullanmaktır :

$ copy <(bar file1) file2
$ copy <(pv file1) file2

Süreç ikamesi geçici fifo boru dosyaları / dev / fd / oluşturan bir bash sihirli şeydir ve stdout'u çalıştırılan işlemden (parantez içinde) bu boru üzerinden bağlar ve kopya onu sıradan bir dosya gibi görür (bir istisna dışında, sadece okuyabilir ileriye doğru).

Güncelleme:

bar komutunun kendisi de kopyalamaya izin verir. Adam çubuğundan sonra:

bar --in-file /dev/rmt/1cbn --out-file \
     tape-restore.tar --size 2.4g --buffer-size 64k

Ancak süreç ikamesi bence bunu yapmanın daha genel bir yoludur. Bir cp programının kendisini kullanır.


3

Ben kullanmayı tercih iletişim ile --gauge param. .Deb paket kurulumlarında ve birçok dağıtımın diğer temel yapılandırma öğelerinde çok sık kullanılır. Yani tekerleği yeniden icat etmenize gerek yok ... tekrar

Sadece 1'den 100'e kadar bir int değeri koyun. Temel ve aptalca bir örnek:

for a in {1..100}; do sleep .1s; echo $a| dialog --gauge "waiting" 7 30; done

Ben pişirme amaçlı bu / bin / Wait dosyası (chmod u + x perms ile) var: P

#!/bin/bash
INIT=`/bin/date +%s`
NOW=$INIT
FUTURE=`/bin/date -d "$1" +%s`
[ $FUTURE -a $FUTURE -eq $FUTURE ] || exit
DIFF=`echo "$FUTURE - $INIT"|bc -l`

while [ $INIT -le $FUTURE -a $NOW -lt $FUTURE ]; do
    NOW=`/bin/date +%s`
    STEP=`echo "$NOW - $INIT"|bc -l`
    SLEFT=`echo "$FUTURE - $NOW"|bc -l`
    MLEFT=`echo "scale=2;$SLEFT/60"|bc -l`
    TEXT="$SLEFT seconds left ($MLEFT minutes)";
    TITLE="Waiting $1: $2"
    sleep 1s
    PTG=`echo "scale=0;$STEP * 100 / $DIFF"|bc -l`
    echo $PTG| dialog --title "$TITLE" --gauge "$TEXT" 7 72
done

if [ "$2" == "" ]; then msg="Espera terminada: $1";audio="Listo";
else msg=$2;audio=$2;fi 

/usr/bin/notify-send --icon=stock_appointment-reminder-excl "$msg"
espeak -v spanish "$audio"

Böylece şunu koyabilirim:

Wait "34 min" "warm up the oven"

veya

Wait "dec 31" "happy new year"


2

benim için kullanımı en kolay ve şimdiye kadar en iyi görünümlü komut pvveya barzaten yazmış bir adam gibi

örneğin: ile tüm sürücünün yedeğini almanız gerekir dd

normalde kullanırsın dd if="$input_drive_path" of="$output_file_path"

ile pvbunu şöyle yapabilirsiniz:

dd if="$input_drive_path" | pv | dd of="$output_file_path"

ve ilerleme doğrudan şu şekilde devam eder STDOUT:

    7.46GB 0:33:40 [3.78MB/s] [  <=>                                            ]

bittikten sonra özet ortaya çıkıyor

    15654912+0 records in
    15654912+0 records out
    8015314944 bytes (8.0 GB) copied, 2020.49 s, 4.0 MB/s

Zamanlayıcı geri sayımı, metin dosyasındaki konum, uygulama kurulumunuz, çalışma zamanı kurulumunuz vb. Gibi farklı işlemlerin ilerlemesini görselleştirmek pvveya kullanabilir misiniz bar?
cprn

2

Birçok cevap, çıktı almak için kendi komutlarınızı yazmayı açıklar '\r' + $some_sort_of_progress_msg . Sorun bazen saniyede yüzlerce güncellemenin yazdırılmasının süreci yavaşlatmasıdır.

Ancak, süreçlerinizden herhangi biri çıktı üretirse (ör. 7z a -r newZipFile myFolder her dosya adını sıkıştırırken çıktılar), daha basit, hızlı, ağrısız ve özelleştirilebilir bir çözüm bulunur.

Python modülünü takın tqdm.

$ sudo pip install tqdm
$ # now have fun
$ 7z a -r -bd newZipFile myFolder | tqdm >> /dev/null
$ # if we know the expected total, we can have a bar!
$ 7z a -r -bd newZipFile myFolder | grep -o Compressing | tqdm --total $(find myFolder -type f | wc -l) >> /dev/null

Yardımı: tqdm -h. Daha fazla seçenek kullanan bir örnek:

$ find / -name '*.py' -exec cat \{} \; | tqdm --unit loc --unit_scale True | wc -l

Bonus olarak tqdmyinelenebilirleri python koduna sarmak için de kullanabilirsiniz .

https://github.com/tqdm/tqdm/blob/master/README.rst#module


Ben "daha fazla seçenek" ile örnek çalışıyor sanmıyorum. tqdmSTDOUT'u wc -lbir borudan geçiriyor gibi görünüyor . Muhtemelen bundan kaçmak istersiniz.
cprn

1
@cprn tqdmilerleme gösterecektir STDERRonun girişini boru ederken STDINetmek STDOUT. Bu durumda , dahil edilmemiş wc -lgibi aynı girişi kim alabilir tqdm?
casper.dcl

Ah, şimdi mantıklı. Açıkladığınız için teşekkürler.
cprn

2

Edouard Lopez'in çalışmasına dayanarak, ekranın boyutuna uyan her ne olursa olsun bir ilerleme çubuğu oluşturdum. Bunu kontrol et.

resim açıklamasını buraya girin

Ayrıca Git Hub'da da yayınlanmıştır .

#!/bin/bash
#
# Progress bar by Adriano Pinaffo
# Available at https://github.com/adriano-pinaffo/progressbar.sh
# Inspired on work by Edouard Lopez (https://github.com/edouard-lopez/progress-bar.sh)
# Version 1.0
# Date April, 28th 2017

function error {
  echo "Usage: $0 [SECONDS]"
  case $1 in
    1) echo "Pass one argument only"
    exit 1
    ;;
    2) echo "Parameter must be a number"
    exit 2
    ;;
    *) echo "Unknown error"
    exit 999
  esac
}

[[ $# -ne 1 ]] && error 1
[[ $1 =~ ^[0-9]+$ ]] || error 2

duration=${1}
barsize=$((`tput cols` - 7))
unity=$(($barsize / $duration))
increment=$(($barsize%$duration))
skip=$(($duration/($duration-$increment)))
curr_bar=0
prev_bar=
for (( elapsed=1; elapsed<=$duration; elapsed++ ))
do
  # Elapsed
prev_bar=$curr_bar
  let curr_bar+=$unity
  [[ $increment -eq 0 ]] || {  
    [[ $skip -eq 1 ]] &&
      { [[ $(($elapsed%($duration/$increment))) -eq 0 ]] && let curr_bar++; } ||
    { [[ $(($elapsed%$skip)) -ne 0 ]] && let curr_bar++; }
  }
  [[ $elapsed -eq 1 && $increment -eq 1 && $skip -ne 1 ]] && let curr_bar++
  [[ $(($barsize-$curr_bar)) -eq 1 ]] && let curr_bar++
  [[ $curr_bar -lt $barsize ]] || curr_bar=$barsize
  for (( filled=0; filled<=$curr_bar; filled++ )); do
    printf "▇"
  done

  # Remaining
  for (( remain=$curr_bar; remain<$barsize; remain++ )); do
    printf " "
  done

  # Percentage
  printf "| %s%%" $(( ($elapsed*100)/$duration))

  # Return
  sleep 1
  printf "\r"
done
printf "\n"
exit 0

Zevk almak



1

Bu sadece gnome zenity kullanılarak uygulanabilir. Zenity, betiklere mükemmel bir yerel arayüz sağlar: https://help.gnome.org/users/zenity/stable/

Zenity Progress Bar Örneğinden:

#!/bin/sh
(
echo "10" ; sleep 1
echo "# Updating mail logs" ; sleep 1
echo "20" ; sleep 1
echo "# Resetting cron jobs" ; sleep 1
echo "50" ; sleep 1
echo "This line will just be ignored" ; sleep 1
echo "75" ; sleep 1
echo "# Rebooting system" ; sleep 1
echo "100" ; sleep 1
) |
zenity --progress \
  --title="Update System Logs" \
  --text="Scanning mail logs..." \
  --percentage=0

if [ "$?" = -1 ] ; then
        zenity --error \
          --text="Update canceled."
fi

1

Ben char tekrarlama için kabuk betiğinde tekrarlanan karakter dizesi oluşturma bir cevap kullandım . İlerleme çubuğunu (örneğin, birçok dosyadan geçen, ancak büyük katran dosyaları veya kopyalama işlemleri için yararlı olmayan bir döngü) görüntülenmesi gereken komut dosyaları için nispeten küçük iki bash sürümüne sahibim . Ne kadar hızlı olursa, biri çubuk görüntüleme için dizeleri hazırlamak için iki işlevden oluşur:

preparebar() {
# $1 - bar length
# $2 - bar char
    barlen=$1
    barspaces=$(printf "%*s" "$1")
    barchars=$(printf "%*s" "$1" | tr ' ' "$2")
}

ve bir ilerleme çubuğu görüntülemek için:

progressbar() {
# $1 - number (-1 for clearing the bar)
# $2 - max number
    if [ $1 -eq -1 ]; then
        printf "\r  $barspaces\r"
    else
        barch=$(($1*barlen/$2))
        barsp=$((barlen-barch))
        printf "\r[%.${barch}s%.${barsp}s]\r" "$barchars" "$barspaces"
    fi
}

Şu şekilde kullanılabilir:

preparebar 50 "#"

yani 50 "#" karakterli çubuk için dizeler hazırlamak ve bundan sonra:

progressbar 35 80

35/80 oranına karşılık gelen "#" karakter sayısını görüntüler:

[#####################                             ]

Siz (veya başka bir program) yeni satır yazdırıncaya kadar, işlevin aynı satırdaki çubuğu tekrar tekrar görüntülediğini unutmayın. İlk parametre olarak -1 koyarsanız, çubuk silinir:

progressbar -1 80

Yavaş sürümün hepsi tek bir işlevdedir:

progressbar() {
# $1 - number
# $2 - max number
# $3 - number of '#' characters
    if [ $1 -eq -1 ]; then
        printf "\r  %*s\r" "$3"
    else
        i=$(($1*$3/$2))
        j=$(($3-i))
        printf "\r[%*s" "$i" | tr ' ' '#'
        printf "%*s]\r" "$j"
    fi
}

ve şu şekilde kullanılabilir (yukarıdakiyle aynı örnek):

progressbar 35 80 50

Stderr'de ilerleme çubuğuna ihtiyacınız varsa >&2, her printf komutunun sonuna ekleyin .


1

Etkinliğin ilerlemesini belirtmek için aşağıdaki komutları deneyin:

while true; do sleep 0.25 && echo -ne "\r\\" && sleep 0.25 && echo -ne "\r|" && sleep 0.25 && echo -ne "\r/" && sleep 0.25 && echo -ne "\r-"; done;

VEYA

while true; do sleep 0.25 && echo -ne "\rActivity: \\" && sleep 0.25 && echo -ne "\rActivity: |" && sleep 0.25 && echo -ne "\rActivity: /" && sleep 0.25 && echo -ne "\rActivity: -"; done;

VEYA

while true; do sleep 0.25 && echo -ne "\r" && sleep 0.25 && echo -ne "\r>" && sleep 0.25 && echo -ne "\r>>" && sleep 0.25 && echo -ne "\r>>>"; sleep 0.25 && echo -ne "\r>>>>"; done;

VEYA

while true; do sleep .25 && echo -ne "\r:Active:" && sleep .25 && echo -ne "\r:aCtive:" && sleep .25 && echo -ne "\r:acTive:" && sleep .25 && echo -ne "\r:actIve:" && sleep .25 && echo -ne "\r:actiVe:" && sleep .25 && echo -ne "\r:activE:"; done;

İlerleme değerini / kapsamını kontrol etmek ve görüntülemek için while döngüsü içindeki bayraklar / değişkenler kullanılabilir .


1

Yukarıda listelenen önerileri kullanarak kendi ilerleme çubuğumu uygulamaya karar verdim.

#!/usr/bin/env bash

main() {
  for (( i = 0; i <= 100; i=$i + 1)); do
    progress_bar "$i"
    sleep 0.1;
  done
  progress_bar "done"
  exit 0
}

progress_bar() {
  if [ "$1" == "done" ]; then
    spinner="X"
    percent_done="100"
    progress_message="Done!"
    new_line="\n"
  else
    spinner='/-\|'
    percent_done="${1:-0}"
    progress_message="$percent_done %"
  fi

  percent_none="$(( 100 - $percent_done ))"
  [ "$percent_done" -gt 0 ] && local done_bar="$(printf '#%.0s' $(seq -s ' ' 1 $percent_done))"
  [ "$percent_none" -gt 0 ] && local none_bar="$(printf '~%.0s' $(seq -s ' ' 1 $percent_none))"

  # print the progress bar to the screen
  printf "\r Progress: [%s%s] %s %s${new_line}" \
    "$done_bar" \
    "$none_bar" \
    "${spinner:x++%${#spinner}:1}" \
    "$progress_message"
}

main "$@"

1
Güzel! ben çizgiyi değiştirmek zorunda çalışma almak percent_none="$(( 100 - "$percent_done" ))"içinpercent_none="$(( 100 - $percent_done))"
sergio

0

Aşağıdakilerden yararlanarak gömülü bir sistem için saf bir kabuk sürümü yaptım:

  • / usr / bin / dd'nin SIGUSR1 sinyal işleme özelliği.

    Temel olarak, bir 'kill SIGUSR1 $ (pid_of_running_dd_process)' gönderirseniz, aktarım hızı ve aktarılan miktarın bir özeti verilir.

  • arka plan dd ve sonra güncellemeler için düzenli olarak sorgulama ve eskiden eskiden ftp istemcileri gibi karma keneler oluşturma.

  • Scp gibi stdout dostu olmayan programların hedefi olarak / dev / stdout kullanılması

Nihai sonuç, her X bayt için bir karma işareti alacağınız eski FTP 'karma' çıktısına benzeyen herhangi bir dosya aktarım işlemi almanıza ve ilerleme güncellemesi almanıza olanak tanır.

Bu neredeyse üretim kalite kodu değil, ama fikri anladınız. Bence çok sevimli.

Değeri ne olursa olsun, gerçek bayt sayımı karma sayısına doğru şekilde yansıtılmayabilir - yuvarlama sorunlarına bağlı olarak bir veya daha fazla olabilir. Bunu bir test senaryosunun parçası olarak kullanma, sadece göz alıcı. Ve evet, bunun çok verimsiz olduğunun farkındayım - bu bir kabuk betiği ve bunun için özür dilemiyorum.

Sonunda sağlanan wget, scp ve tftp örnekleri. Veri yayan herhangi bir şeyle çalışmalıdır. Stdout dostu olmayan programlar için / dev / stdout kullandığınızdan emin olun.

#!/bin/sh
#
# Copyright (C) Nathan Ramella (nar+progress-script@remix.net) 2010 
# LGPLv2 license
# If you use this, send me an email to say thanks and let me know what your product
# is so I can tell all my friends I'm a big man on the internet!

progress_filter() {

        local START=$(date +"%s")
        local SIZE=1
        local DURATION=1
        local BLKSZ=51200
        local TMPFILE=/tmp/tmpfile
        local PROGRESS=/tmp/tftp.progress
        local BYTES_LAST_CYCLE=0
        local BYTES_THIS_CYCLE=0

        rm -f ${PROGRESS}

        dd bs=$BLKSZ of=${TMPFILE} 2>&1 \
                | grep --line-buffered -E '[[:digit:]]* bytes' \
                | awk '{ print $1 }' >> ${PROGRESS} &

        # Loop while the 'dd' exists. It would be 'more better' if we
        # actually looked for the specific child ID of the running 
        # process by identifying which child process it was. If someone
        # else is running dd, it will mess things up.

        # My PID handling is dumb, it assumes you only have one running dd on
        # the system, this should be fixed to just get the PID of the child
        # process from the shell.

        while [ $(pidof dd) -gt 1 ]; do

                # PROTIP: You can sleep partial seconds (at least on linux)
                sleep .5    

                # Force dd to update us on it's progress (which gets
                # redirected to $PROGRESS file.
                # 
                # dumb pid handling again
                pkill -USR1 dd

                local BYTES_THIS_CYCLE=$(tail -1 $PROGRESS)
                local XFER_BLKS=$(((BYTES_THIS_CYCLE-BYTES_LAST_CYCLE)/BLKSZ))

                # Don't print anything unless we've got 1 block or more.
                # This allows for stdin/stderr interactions to occur
                # without printing a hash erroneously.

                # Also makes it possible for you to background 'scp',
                # but still use the /dev/stdout trick _even_ if scp
                # (inevitably) asks for a password. 
                #
                # Fancy!

                if [ $XFER_BLKS -gt 0 ]; then
                        printf "#%0.s" $(seq 0 $XFER_BLKS)
                        BYTES_LAST_CYCLE=$BYTES_THIS_CYCLE
                fi
        done

        local SIZE=$(stat -c"%s" $TMPFILE)
        local NOW=$(date +"%s")

        if [ $NOW -eq 0 ]; then
                NOW=1
        fi

        local DURATION=$(($NOW-$START))
        local BYTES_PER_SECOND=$(( SIZE / DURATION ))
        local KBPS=$((SIZE/DURATION/1024))
        local MD5=$(md5sum $TMPFILE | awk '{ print $1 }')

        # This function prints out ugly stuff suitable for eval() 
        # rather than a pretty string. This makes it a bit more 
        # flexible if you have a custom format (or dare I say, locale?)

        printf "\nDURATION=%d\nBYTES=%d\nKBPS=%f\nMD5=%s\n" \
            $DURATION \
            $SIZE \
            $KBPS \
            $MD5
}

Örnekler:

echo "wget"
wget -q -O /dev/stdout http://www.blah.com/somefile.zip | progress_filter

echo "tftp"
tftp -l /dev/stdout -g -r something/firmware.bin 192.168.1.1 | progress_filter

echo "scp"
scp user@192.168.1.1:~/myfile.tar /dev/stdout | progress_filter

İyi bir fikir, dosya boyutu önceden olduğu sürece bu şekilde pv'den daha fazla değer sağlayabilir, ancak körü körüne sinyal pidof ddkorkutucu.

'# PID kullanımım aptal'
synthesizerpatel

Belki de yakalayabilir $!gelen ddve bekleyin [[ -e /proc/${DD_PID} ]].

0

Geçici bir ilerleme çubuğu göstermeniz gerekiyorsa (gösterim zamanını önceden bilerek), Python'u aşağıdaki gibi kullanabilirsiniz:

#!/bin/python
from time import sleep
import sys

if len(sys.argv) != 3:
    print "Usage:", sys.argv[0], "<total_time>", "<progressbar_size>"
    exit()

TOTTIME=float(sys.argv[1])
BARSIZE=float(sys.argv[2])

PERCRATE=100.0/TOTTIME
BARRATE=BARSIZE/TOTTIME

for i in range(int(TOTTIME)+1):
    sys.stdout.write('\r')
    s = "[%-"+str(int(BARSIZE))+"s] %d%% "
    sys.stdout.write(s % ('='*int(BARRATE*i), int(PERCRATE*i)))
    sys.stdout.flush()
    SLEEPTIME = 1.0
    if i == int(TOTTIME): SLEEPTIME = 0.1
    sleep(SLEEPTIME)
print ""

Ardından, Python komut dosyasını olarak kaydettiğinizi varsayarsak progressbar.py, aşağıdaki komutu çalıştırarak ilerleme çubuğunu bash komut dosyanızdan göstermek mümkündür:

python progressbar.py 10 50

Bir ilerleme çubuğu boyutundaki 50karakterleri ve 10saniyeler boyunca "çalışıyor" u gösterir .


0

Korku tarafından verilen cevap üzerine inşa ettim

Bu, RMAN geri yüklemesinin ilerlemesini almak için bir Oracle veritabanına bağlanır.

#!/bin/bash

 # 1. Create ProgressBar function
 # 1.1 Input is currentState($1) and totalState($2)
 function ProgressBar {
 # Process data
let _progress=(${1}*100/${2}*100)/100
let _done=(${_progress}*4)/10
let _left=40-$_done
# Build progressbar string lengths
_fill=$(printf "%${_done}s")
_empty=$(printf "%${_left}s")

# 1.2 Build progressbar strings and print the ProgressBar line
# 1.2.1 Output example:
# 1.2.1.1 Progress : [########################################] 100%
printf "\rProgress : [${_fill// /#}${_empty// /-}] ${_progress}%%"

}

function rman_check {
sqlplus -s / as sysdba <<EOF
set heading off
set feedback off
select
round((sofar/totalwork) * 100,0) pct_done
from
v\$session_longops
where
totalwork > sofar
AND
opname NOT LIKE '%aggregate%'
AND
opname like 'RMAN%';
exit
EOF
}

# Variables
_start=1

# This accounts as the "totalState" variable for the ProgressBar function
_end=100

_rman_progress=$(rman_check)
#echo ${_rman_progress}

# Proof of concept
#for number in $(seq ${_start} ${_end})

while [ ${_rman_progress} -lt 100 ]
do

for number in _rman_progress
do
sleep 10
ProgressBar ${number} ${_end}
done

_rman_progress=$(rman_check)

done
printf '\nFinished!\n'

0
#!/bin/bash

function progress_bar() {
    bar=""
    total=10
    [[ -z $1 ]] && input=0 || input=${1}
    x="##"
   for i in `seq 1 10`; do
        if [ $i -le $input ] ;then
            bar=$bar$x
        else
            bar="$bar  "
       fi
    done
    #pct=$((200*$input/$total % 2 + 100*$input/$total))
    pct=$(($input*10))
    echo -ne "Progress : [ ${bar} ] (${pct}%) \r"    
    sleep 1
    if [ $input -eq 10 ] ;then
        echo -ne '\n'
    fi

}

bunu, çubuk sayısı için 1-10 diyelim bir ölçekte çizen bir işlev oluşturabilir:

progress_bar 1
echo "doing something ..."
progress_bar 2
echo "doing something ..."
progress_bar 3
echo "doing something ..."
progress_bar 8
echo "doing something ..."
progress_bar 10

0
#!/bin/bash
tot=$(wc -c /proc/$$/fd/255 | awk '/ /{print $1}')
now() {
echo $(( 100* ($(awk '/^pos:/{print $2}' < /proc/$$/fdinfo/255)-166) / (tot-166) )) "%"
}
now;
now;
now;
now;
now;
now;
now;
now;
now;

çıktı:

0 %
12 %
25 %
37 %
50 %
62 %
75 %
87 %
100 %

not: 255 yerine 1 koyarsanız, standardı 2 ile standart dışı olarak izlersiniz (ancak kaynağı "tot" u yansıtılan çıktı dosyası boyutuna ayarlamak için değiştirmeniz gerekir)

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.