Bagaimana cara menambahkan progress bar ke skrip shell?


413

Saat membuat skrip dalam bash atau shell lain di * NIX, saat menjalankan perintah yang akan memakan waktu lebih dari beberapa detik, bilah kemajuan diperlukan.

Misalnya, menyalin file besar, membuka file tar besar.

Cara apa yang Anda rekomendasikan untuk menambahkan progress bar ke skrip shell?


Lihat juga stackoverflow.com/questions/12498304/... untuk contoh-contoh logika kontrol (latar belakang pekerjaan dan lakukan sesuatu sampai selesai).
tripleee

1
Ada serangkaian persyaratan yang sering kami temukan berguna saat membuat skrip. logging, menampilkan progres, warna, output mewah dll ... Saya selalu merasa harus ada semacam kerangka penulisan skrip sederhana. Akhirnya saya memutuskan untuk mengimplementasikannya karena saya tidak bisa menemukannya. Anda mungkin menemukan ini membantu. Ini murni bash, maksudku Just Bash. github.com/SumuduLansakara/JustBash
Sumudu

Bukankah ini harus dipindahkan ke unix.stackexchange.com ?
Ethan

Jawaban:


685

Anda dapat menerapkan ini dengan menimpa garis. Gunakan \runtuk kembali ke awal baris tanpa menulis \nke terminal.

Tulis \nketika Anda sudah selesai untuk memajukan garis.

Gunakan echo -neuntuk:

  1. tidak mencetak \ndan
  2. untuk mengenali urutan melarikan diri seperti \r.

Ini demo:

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

Dalam komentar di bawah ini, puk menyebutkan ini "gagal" jika Anda mulai dengan garis panjang dan kemudian ingin menulis garis pendek: Dalam hal ini, Anda harus menimpa panjang garis panjang (misalnya, dengan spasi).


23
Menurut gema halaman manual (setidaknya di MacOS X) sh / bash menggunakan mereka sendiri built-in gema perintah yang tidak menerima "-n" ... sehingga untuk mencapai hal yang sama Anda perlu menempatkan \ r \ c pada akhir string, bukan hanya \ r
Justin Jenkins

51
Cara portabel untuk output ini adalah dengan menggunakan printfbukan echo.
Jens

9
untuk printf kita harus menggunakan format ini:, printf "#### (50%%)\r"itu tidak akan bekerja dengan tanda kutip tunggal dan tanda persen perlu diloloskan.
nurettin

7
Saya tidak mendapatkan ini - diterima dan tumpukan upvotes untuk hack "Saya kira berapa lama operasi ini akan mengambil perangkat keras yang tidak dikenal"? pv adalah jawaban yang benar IMO (tetapi bar juga akan melakukannya)
Stephen

19
Pertanyaannya adalah "Bagaimana saya melakukan progress bar" dengan contoh menyalin file. Saya fokus pada masalah "grafis", bukan perhitungan seberapa jauh sepanjang operasi copy file.
Mitch Haile

73

Anda juga mungkin tertarik dengan cara melakukan pemintal :

Bisakah saya melakukan pemintal di Bash?

Tentu!

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

Setiap kali loop berulang, ini akan menampilkan karakter berikutnya dalam string sp, membungkus saat mencapai akhir. (i adalah posisi karakter saat ini untuk ditampilkan dan $ {# sp} adalah panjang dari string sp).

String \ b digantikan oleh karakter 'backspace'. Atau, Anda dapat bermain dengan \ r untuk kembali ke awal baris.

Jika Anda ingin memperlambat, masukkan perintah sleep di dalam loop (setelah printf).

Setara POSIX akan menjadi:

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

Jika Anda sudah memiliki loop yang bekerja banyak, Anda dapat memanggil fungsi berikut di awal setiap iterasi untuk memperbarui spinner:

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
Versi yang jauh lebih pendek, sepenuhnya portabel *: while :;do for s in / - \\ \|; do printf "\r$s";sleep .1;done;done(*: sleepmungkin memerlukan int daripada desimal)
Adam Katz

1
@Daenyth. Terima kasih. Mohon di mana kita harus memanggil perintah yang perlu kita perhatikan sedang berlangsung menggunakan kode sebelumnya?
goro

@goro: Pada some_work ...baris di atas; diskusi yang lebih terperinci yang dibangun berdasarkan jawaban yang bermanfaat ini dan komentar Adam Katz yang bermanfaat - dengan fokus pada kepatuhan POSIX - dapat ditemukan di sini .
mklement0

@AdamKatz: Itu penyederhanaan yang berguna dan mudah dibawa-bawa, tetapi untuk mencocokkan pendekatan Daenyth, pemintal harus didasarkan \bdaripada \r, karena selain itu hanya akan bekerja pada awal baris: while :; do for c in / - \\ \|; do printf '%s\b' "$c"; sleep 1; done; done- atau, jika menampilkan kursor di belakang pemintal tidak diinginkan:printf ' ' && while :; do for c in / - \\ \|; do printf '\b%s' "$c"; sleep 1; done; done
mklement0

1
@kaushal - Ctrl + C akan menghentikannya secara manual. Jika Anda memiliki pekerjaan latar belakang, Anda dapat menyimpan PID-nya ( job=$!) dan kemudian jalankan while kill -0 $job 2>/dev/null;do …, misalnya: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

Beberapa posting telah menunjukkan cara menampilkan progres perintah. Untuk menghitungnya, Anda harus melihat seberapa banyak kemajuan Anda. Pada sistem BSD beberapa perintah, seperti dd (1), menerima SIGINFOsinyal, dan akan melaporkan progresnya. Pada sistem Linux, beberapa perintah akan merespons serupa SIGUSR1. Jika fasilitas ini tersedia, Anda dapat mengirim masukan melalui Andadd mengirimkan untuk memantau jumlah byte yang diproses.

Atau, Anda dapat menggunakan lsofuntuk mendapatkan offset dari pointer baca file, dan dengan demikian menghitung progresnya. Saya telah menulis sebuah perintah, bernama pmonitor , yang menampilkan progres pemrosesan suatu proses atau file yang ditentukan. Dengannya Anda bisa melakukan hal-hal, seperti berikut ini.

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

Versi skrip shell Linux dan FreeBSD yang lebih lama muncul di blog saya .


Ini luar biasa, saya selalu lupa menyambungkan hal-hal melalui pv :-) Saya pikir perintah "stat" saya bekerja sedikit berbeda, versi saya (Linux) dari skrip ini: gist.github.com/unhammer/b0ab6a6aa8e1eeaf236b
unhammer

Pos luar biasa, selalu suka saat awkdimainkan!
ShellFish

Ini bagus! Terima kasih untuk skrip yang mengagumkan!
thebeagle

47

Mendapat fungsi progress bar yang mudah yang saya tulis di hari lain:

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

Atau ambil dari,
https://github.com/fearside/ProgressBar/


dapatkah Anda menjelaskan baris di bawah 1.2.1.1? Apakah Anda melakukan substitusi sed dengan variabel _fill dan _empty? Saya bingung.
Chirag

Alih-alih menggunakan sed, saya menggunakan bash internal "Substring Replacement", karena ini adalah pekerjaan yang mudah, saya lebih suka menggunakan fungsi internal bash untuk jenis pekerjaan ini. Kode juga terlihat lebih bagus. :-) Periksa di sini tldp.org/LDP/abs/html/string-manipulation.html dan cari penggantian substring.
fearside

dan $ {_ fill} ditetapkan sebagai jumlah spasi $ {_ selesai}. Ini indah. Pria yang baik. Saya pasti akan menggunakan ini di semua skrip bash saya haha
Chirag

Kerja bagus @fearside! Saya melakukan sedikit tweak untuk melewatkan ketika _progress tidak berubah dari nilai terakhir, untuk meningkatkan kecepatan. github.com/enobufs/bash-tools/blob/master/bin/progbar
enobufs

Manis. Mengubah dasbor dengan persegi panjang memberikan tampilan dan nuansa yang lebih profesional:printf "\rProgress : [${_fill// /▇}${_empty// / }] ${_progress}%%"
Mehdi LAMRANI

44

gunakan perintah linux pv:

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

ia tidak tahu ukurannya jika berada di tengah-tengah sungai, tetapi ia memberikan kecepatan dan total dan dari sana Anda dapat mengetahui berapa lama waktu yang diperlukan dan mendapatkan umpan balik sehingga Anda tahu itu tidak menggantung.


32

Saya mencari sesuatu yang lebih seksi daripada jawaban yang dipilih, begitu juga skrip saya sendiri.

Pratinjau

progress-bar.sh beraksi

Sumber

Saya menaruhnya di githubprogress-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
}

Pemakaian

 progress-bar 100

1
Saya tidak mengerti bagaimana ini diintegrasikan ke dalam beberapa pemrosesan di mana panjang proses tidak diketahui. Bagaimana cara menghentikan progress bar jika proses saya selesai lebih awal, misal untuk unzipping file.
Januari

Saya pikir penggunaannya seharusnyaprogress-bar 100
jirarium

Kemajuan yang menarik memang. Bagaimana itu bisa dikaitkan dengan fungsi yang memproses tindakan berkepanjangan pada server jauh melalui ssh? Maksud saya, bagaimana mungkin mengukur waktu pemutakhiran (misalnya) pada server jarak jauh?
berwajah

1
@faceless itu bukan dalam lingkup kode ini Anda berikan waktu dan itu mundur
Édouard Lopez

1
@Fusion adalah karakter unicode (U + 2587 LOWER SEVEN EIGHTHS BLOCK) yang seharusnya aman untuk shell modern. Cobalah env Anda
Édouard Lopez

18

GNU tar memiliki opsi berguna yang memberikan fungsionalitas bilah kemajuan sederhana.

(...) Tindakan pos pemeriksaan lain yang tersedia adalah 'titik' (atau '.'). Ini menginstruksikan tar untuk mencetak satu titik pada aliran daftar standar, misalnya:

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

Efek yang sama dapat diperoleh dengan:

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

+1 untuk pendekatan paling sederhana! Jika Anda melihat tidak ada titik yang dicetak, coba kurangi jumlahnya, misalnya --checkpoint=.10. Ini juga berfungsi baik ketika mengekstraksi dengan tar -xz.
Noam Manos

13

Metode yang lebih sederhana yang bekerja pada sistem saya menggunakan utilitas pipeview (pv).

srcdir=$1
outfile=$2


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

13

Belum pernah melihat yang serupa dan semua fungsi khusus di sini tampaknya fokus pada rendering saja jadi ... solusi patuh POSIX saya yang sangat sederhana di bawah ini dengan penjelasan langkah demi langkah karena pertanyaan ini tidak sepele.

TL; DR

Rendering progress bar sangat mudah. Memperkirakan berapa banyak yang harus disajikan adalah masalah yang berbeda. Ini adalah cara merender (menghidupkan) bilah kemajuan - Anda dapat menyalin & menempelkan contoh ini ke file dan menjalankannya:

#!/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} - nilai dari 1 hingga 20
  • echo -n - cetak tanpa garis baru di akhir
  • echo -e - menafsirkan karakter khusus saat mencetak
  • "\r" - carriage return, char khusus untuk kembali ke awal baris

Anda dapat membuatnya menyajikan konten apa pun dengan kecepatan apa pun sehingga metode ini sangat universal, misalnya sering digunakan untuk visualisasi "peretasan" dalam film konyol, tanpa bercanda.

Jawaban penuh

Daging masalahnya adalah bagaimana menentukan $inilai, yaitu berapa banyak progress bar untuk ditampilkan. Dalam contoh di atas saya hanya membiarkannya bertambah dalam forlingkaran untuk menggambarkan prinsip tetapi aplikasi kehidupan nyata akan menggunakan loop tak terbatas dan menghitung $ivariabel pada setiap iterasi. Untuk membuat perhitungan tersebut diperlukan bahan-bahan berikut:

  1. berapa banyak pekerjaan yang harus dilakukan
  2. berapa banyak pekerjaan yang telah dilakukan sejauh ini

Dalam kasus cpitu perlu ukuran file sumber dan ukuran file target:

#!/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 - periksa statistik file
  • -c - mengembalikan nilai yang diformat
  • %s - ukuran total

Dalam hal operasi seperti membongkar file, menghitung ukuran sumber sedikit lebih sulit tetapi masih semudah mendapatkan ukuran file yang tidak terkompresi:

#!/bin/sh
src_size=$(gzip -l "$src" | tail -n1 | tr -s ' ' | cut -d' ' -f3)
  • gzip -l - Menampilkan info tentang arsip zip
  • tail -n1 - bekerja dengan 1 baris dari bawah
  • tr -s ' ' - menerjemahkan beberapa spasi menjadi satu (tekan)
  • cut -d' ' -f3 - potong kolom ke-3 yang dibatasi ruang

Tapi inilah masalahnya. Solusi ini semakin tidak umum. Semua perhitungan kemajuan aktual terikat erat dengan domain yang Anda coba visualisasikan, apakah itu operasi file tunggal, penghitung waktu mundur, peningkatan jumlah file dalam direktori, operasi pada banyak file, dll., Oleh karena itu, tidak bisa digunakan kembali. Satu-satunya bagian yang dapat digunakan kembali adalah rendering progress bar. Untuk menggunakannya kembali, Anda perlu mengabstraksikan dan menyimpannya dalam file (mis. /usr/lib/progress_bar.sh), Lalu mendefinisikan fungsi yang menghitung nilai input khusus untuk domain Anda. Beginilah tampilan kode yang digeneralisasi (saya juga membuat $BARdinamis karena orang memintanya, sisanya harus jelas sekarang):

#!/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 - bawaan untuk mencetak barang dalam format yang diberikan
  • printf '%50s' - cetak apa-apa, pad dengan 50 spasi
  • tr ' ' '#' - menerjemahkan setiap spasi menjadi tanda pagar

Dan inilah cara Anda menggunakannya:

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

Jelas itu dapat dibungkus dalam suatu fungsi, ditulis ulang untuk bekerja dengan aliran pipa, ditulis ulang ke bahasa lain, apa pun racun Anda.


1
Bagi mereka yang menginginkan hal yang paling sederhana, saya hanya membuat milik saya dengan jawaban pertama cprn. Ini adalah bilah kemajuan yang sangat sederhana dalam suatu fungsi yang menggunakan beberapa aturan proporsionalitas bodoh untuk menggambar bilah: pastebin.com/9imhRLYX
YCN-


9

Bilah progres gaya APT (Tidak merusak output normal)

masukkan deskripsi gambar di sini

EDIT: Untuk versi yang diperbarui periksa halaman github saya

Saya tidak puas dengan jawaban atas pertanyaan ini. Apa yang saya cari secara pribadi adalah bilah kemajuan mewah seperti yang terlihat oleh APT.

Saya telah melihat kode sumber C untuk APT dan memutuskan untuk menulis padanan saya sendiri untuk bash.

Baris kemajuan ini akan tetap baik di bagian bawah terminal dan tidak akan mengganggu output yang dikirim ke terminal.

Harap perhatikan bahwa bilah saat ini diperbaiki dengan lebar 100 karakter. Jika Anda ingin mengaturnya dengan ukuran terminal, ini juga cukup mudah untuk dilakukan (Versi yang diperbarui pada halaman github saya juga menangani ini).

Saya akan memposting skrip saya di sini. Contoh penggunaan:

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

Script (Saya sangat merekomendasikan versi di github saya sebagai gantinya):

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

Ini memungkinkan Anda memvisualisasikan bahwa suatu perintah masih dijalankan:

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

Ini akan membuat loop tak terbatas sementara yang dijalankan di latar belakang dan menggandakan "." setiap detik. Ini akan ditampilkan .di shell. Jalankan tarperintah atau perintah yang Anda inginkan. Ketika perintah itu selesai dieksekusi kemudian bunuh pekerjaan terakhir yang berjalan di latar belakang - yang merupakan loop sementara tak terbatas .


Tidak bisakah pekerjaan lain dimulai di latar belakang selama eksekusi dan berpotensi terbunuh alih-alih loop kemajuan?
Centimane

Saya pikir idenya adalah Anda akan meletakkan ini dalam skrip, jadi ini hanya akan menjebak keluarnya skrip itu.
Iguananaut

1
Saya suka perintah ini, saya menggunakannya dalam file saya. Saya hanya sedikit gelisah karena saya tidak begitu mengerti cara kerjanya. Baris pertama dan ketiga lebih mudah dimengerti, tapi saya masih tidak yakin. Saya tahu ini adalah jawaban lama, tetapi apakah ada cara saya bisa mendapatkan penjelasan yang berbeda untuk pemula di program
Felipe

1
Ini adalah HANYA jawaban yang benar, di mana orang lain hanya Scripting 101 progress bar mainan yang tidak berarti apa-apa dan tidak digunakan untuk program nyata, sekali saja, tidak dapat dilacak (hampir SEMUA). Terima kasih.
bekce

@Felipe, Loop sementara adalah proses latar belakang. $! di perangkap pertama menangkap id proses dari proses latar belakang itu dan memastikan bahwa jika proses saat ini / induk berakhir proses latar belakang mati juga dan itu tidak dibiarkan menggantung. Pernyataan kill hanya mengakhiri proses latar belakang ketika perintah panjang atau perintah Anda berakhir.
floydn

7

Berikut ini tampilannya

Mengunggah file

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

Menunggu pekerjaan selesai

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

Fungsi sederhana yang mengimplementasikannya

Anda cukup menyalin-menempelnya ke skrip Anda. Tidak memerlukan hal lain untuk bekerja.

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"
}

Contoh penggunaan

Di sini, kami mengunggah file dan menggambar ulang bilah kemajuan di setiap iterasi. Tidak masalah pekerjaan apa yang sebenarnya dilakukan selama kita bisa mendapatkan 2 nilai: nilai maks dan nilai saat ini.

Dalam contoh di bawah ini nilai maks adalah file_sizedan nilai saat ini disediakan oleh beberapa fungsi dan dipanggil 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"

Fungsi rapi dan sederhana. Terima kasih banyak!
Andreas Kraft

Ini yang saya cari! Terima kasih banyak :)
wajdi_jurry

4

Sebagian besar perintah unix tidak akan memberi Anda semacam umpan balik langsung dari mana Anda bisa melakukan ini. Beberapa akan memberi Anda output pada stdout atau stderr yang dapat Anda gunakan.

Untuk sesuatu seperti tar, Anda bisa menggunakan -v switch dan menyalurkan output ke program yang memperbarui animasi kecil untuk setiap baris yang dibacanya. Sebagai tar menulis daftar file itu terurai program dapat memperbarui animasi. Untuk menyelesaikan satu persen, Anda harus mengetahui jumlah file dan menghitung baris.

cp tidak memberikan output semacam ini sejauh yang saya tahu. Untuk memantau perkembangan cp, Anda harus memantau sumber dan tujuan file dan melihat ukuran tujuan. Anda bisa menulis program c kecil menggunakan panggilan sistem stat (2) untuk mendapatkan ukuran file. Ini akan membaca ukuran sumber kemudian polling file tujuan dan memperbarui bar% lengkap berdasarkan ukuran file yang ditulis hingga saat ini.


4

Solusi saya menampilkan persentase tarball yang saat ini sedang dikompresi dan ditulis. Saya menggunakan ini saat menulis gambar filesystem root 2GB. Anda benar-benar membutuhkan bilah kemajuan untuk hal-hal ini. Apa yang saya lakukan adalah menggunakan gzip --list untuk mendapatkan ukuran tarball yang tidak terkompresi. Dari itu saya menghitung faktor pemblokiran yang diperlukan untuk membagi file menjadi 100 bagian. Akhirnya, saya mencetak pesan pos pemeriksaan untuk setiap blok. Untuk file 2GB ini memberikan sekitar 10MB blok. Jika itu terlalu besar maka Anda dapat membagi BLOCKING_FACTOR dengan 10 atau 100, tetapi kemudian lebih sulit untuk mencetak hasil yang cantik dalam hal persentase.

Dengan asumsi Anda menggunakan Bash maka Anda dapat menggunakan fungsi shell berikut

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}
}

Solusi yang bagus tetapi bagaimana Anda melakukannya ketika Anda ingin mengompres direktori?
Samir Sadek

4

Pertama-tama bar bukan satu-satunya meteran progres pipa. Yang lain (mungkin bahkan lebih dikenal) adalah pv (penampil pipa).

Bilah dan pv kedua dapat digunakan misalnya seperti ini:

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

atau bahkan:

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

salah satu trik yang berguna jika Anda ingin menggunakan bar dan pv dalam perintah yang bekerja dengan file yang diberikan dalam argumen, seperti misalnya salin file1 file2, adalah dengan menggunakan proses substitusi :

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

Substitusi proses adalah hal bash magic yang membuat file pipa fifo sementara / dev / fd / dan menghubungkan stdout dari proses yang dijalankan (di dalam tanda kurung) melalui pipa ini dan menyalin melihatnya seperti file biasa (dengan satu pengecualian, hanya dapat membacanya ke depan).

Memperbarui:

perintah bar itu sendiri memungkinkan juga untuk menyalin. Setelah bar pria:

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

Tetapi proses substitusi menurut saya merupakan cara yang lebih umum untuk melakukannya. Itu menggunakan program cp itu sendiri.


3

Saya lebih suka menggunakan dialog dengan param --gauge . Sangat sering digunakan dalam instalasi paket deb dan hal-hal konfigurasi dasar lainnya dari banyak distro. Jadi, Anda tidak perlu menemukan kembali roda ... lagi

Masukkan nilai int dari 1 hingga 100 @stdin. Satu contoh dasar dan konyol:

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

Saya memiliki file / bin / Tunggu ini (dengan chmod u + x perms) untuk keperluan memasak: 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"

Jadi saya bisa meletakkan:

Wait "34 min" "warm up the oven"

atau

Wait "dec 31" "happy new year"


2

bagi saya yang paling mudah digunakan dan yang paling baik dilihat sejauh ini adalah perintah pvatau barseperti yang sudah ditulis oleh beberapa orang

misalnya: perlu membuat cadangan seluruh drive dengan dd

biasanya Anda gunakan dd if="$input_drive_path" of="$output_file_path"

dengan pvAnda dapat membuatnya seperti ini:

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

dan progresnya langsung STDOUTseperti ini:

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

setelah selesai ringkasan muncul

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

Bisakah Anda menggunakan pvatau baruntuk memvisualisasikan kemajuan proses yang berbeda, misalnya penghitung waktu mundur, posisi dalam file teks, instalasi aplikasi Anda, pengaturan runtime, dll.?
cprn

2

Banyak jawaban menjelaskan menulis perintah Anda sendiri untuk dicetak '\r' + $some_sort_of_progress_msg. Masalahnya kadang-kadang adalah bahwa mencetak ratusan pembaruan ini per detik akan memperlambat proses.

Namun, jika ada proses Anda menghasilkan output (misalnya 7z a -r newZipFile myFolderakan menampilkan setiap nama file saat dikompres) maka ada solusi yang lebih sederhana, cepat, tidak menyakitkan dan dapat disesuaikan.

Instal modul python 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

Bantuan: tqdm -h. Contoh menggunakan lebih banyak opsi:

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

Sebagai bonus, Anda juga dapat menggunakan tqdmuntuk membungkus iterables dalam kode python.

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


Saya rasa contoh Anda dengan "opsi lainnya" tidak berfungsi. Tampaknya melewati tqdmSTDOUT wc -lmelalui pipa. Anda mungkin ingin menghindarinya.
cprn

1
@ cprn tqdmakan menunjukkan kemajuan STDERRsaat memasukkan inputnya STDINke STDOUT. Dalam hal ini, wc -lsiapa yang akan menerima input yang sama seolah-olah tqdmtidak dimasukkan.
casper.dcl

Ah, masuk akal sekarang. Terima kasih telah menjelaskan.
cprn

2

Berdasarkan karya Edouard Lopez, saya membuat progress bar yang sesuai dengan ukuran layar, apa pun itu. Coba lihat.

masukkan deskripsi gambar di sini

Ini juga diposting di Git Hub .

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

Nikmati



1

Ini hanya berlaku menggunakan gnome zenity. Zenity menyediakan antarmuka asli yang bagus untuk skrip bash: https://help.gnome.org/users/zenity/stable/

Dari Contoh Zenity Progress Bar:

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

Saya menggunakan jawaban dari Membuat string karakter yang diulang dalam skrip shell untuk pengulangan char. Saya memiliki dua versi bash yang relatif kecil untuk skrip yang perlu menampilkan progress bar (misalnya, loop yang melewati banyak file, tetapi tidak berguna untuk file tar besar atau operasi salin). Yang lebih cepat terdiri dari dua fungsi, satu untuk menyiapkan string untuk tampilan bar:

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

dan satu untuk menampilkan bilah kemajuan:

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
}

Ini dapat digunakan sebagai:

preparebar 50 "#"

yang berarti menyiapkan string untuk bilah dengan 50 "#" karakter, dan setelah itu:

progressbar 35 80

akan menampilkan jumlah karakter "#" yang sesuai dengan rasio 35/80:

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

Ketahuilah bahwa fungsi menampilkan bilah pada baris yang sama berulang-ulang sampai Anda (atau program lain) mencetak baris baru. Jika Anda menempatkan -1 sebagai parameter pertama, bilah akan dihapus:

progressbar -1 80

Versi lebih lambat semuanya dalam satu fungsi:

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
}

dan itu dapat digunakan sebagai (contoh yang sama seperti di atas):

progressbar 35 80 50

Jika Anda memerlukan progressbar pada stderr, tambahkan saja >&2di akhir setiap perintah printf.


1

Untuk menunjukkan kemajuan aktivitas, coba perintah berikut:

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;

ATAU

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;

ATAU

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;

ATAU

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;

Seseorang dapat menggunakan flag / variabel di dalam loop sementara untuk memeriksa dan menampilkan nilai / tingkat kemajuan.


1

Menggunakan saran yang tercantum di atas, saya memutuskan untuk menerapkan bilah kemajuan saya sendiri.

#!/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
Bagus! untuk membuatnya bekerja, saya harus mengubah jalur percent_none="$(( 100 - "$percent_done" ))"kepercent_none="$(( 100 - $percent_done))"
sergio

0

Saya melakukan versi shell murni untuk sistem embedded mengambil keuntungan dari:

  • Fitur penanganan sinyal SIGUSR1 / usr / bin / dd.

    Pada dasarnya, jika Anda mengirim 'kill SIGUSR1 $ (pid_of_running_dd_process)', itu akan menampilkan ringkasan kecepatan dan jumlah throughput yang ditransfer.

  • backgrounding dd dan kemudian meminta secara teratur untuk pembaruan, dan menghasilkan kutu hash seperti dulu ftp klien.

  • Menggunakan / dev / stdout sebagai tujuan untuk program ramah non-stdout seperti scp

Hasil akhirnya memungkinkan Anda untuk mengambil operasi transfer file apa pun dan mendapatkan pembaruan kemajuan yang terlihat seperti keluaran 'hash' FTP sekolah lama di mana Anda hanya akan mendapatkan tanda pagar untuk setiap X byte.

Ini bukan kode kualitas produksi, tetapi Anda mendapatkan idenya. Saya pikir itu lucu.

Untuk apa nilainya, byte-count yang sebenarnya mungkin tidak tercermin dengan benar dalam jumlah hash - Anda mungkin memiliki satu lebih atau kurang tergantung pada masalah pembulatan. Jangan gunakan ini sebagai bagian dari skrip tes, itu hanya eye-candy. Dan, ya, saya sadar ini sangat tidak efisien - ini adalah shell script dan saya tidak meminta maaf untuk itu.

Contoh dengan wget, scp dan tftp disediakan di akhir. Ini harus bekerja dengan apa pun yang memancarkan data. Pastikan untuk menggunakan / dev / stdout untuk program yang tidak ramah stdout.

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

Contoh:

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

Gagasan yang layak, selama Anda memiliki ukuran file sebelumnya, Anda dapat memberikan nilai tambah daripada pv dengan cara ini, tetapi memberi sinyal secara membabi buta bahwa pidof dditu menakutkan.

Mencoba menyebut itu dengan '# Penanganan PID saya bodoh'
synthesizerpatel

Anda mungkin dapat menangkap $!dari dddan menunggu [[ -e /proc/${DD_PID} ]].

0

Jika Anda harus menunjukkan bilah kemajuan temporal (dengan mengetahui sebelumnya waktu yang ditampilkan), Anda dapat menggunakan Python sebagai berikut:

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

Kemudian, dengan asumsi Anda menyimpan skrip Python sebagai progressbar.py, dimungkinkan untuk menampilkan bilah progres dari skrip bash Anda dengan menjalankan perintah berikut:

python progressbar.py 10 50

Itu akan menampilkan 50karakter ukuran bar kemajuan dan "berjalan" selama beberapa 10detik.


0

Saya telah membangun jawaban yang diberikan oleh sisi ketakutan

Ini terhubung ke database Oracle untuk mengambil progres pengembalian RMAN.

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

}

dapat membuat fungsi yang menggambar ini pada skala katakanlah 1-10 untuk jumlah bar:

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;

keluaran:

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

Catatan: jika alih-alih 255 Anda meletakkan 1 Anda akan memantau standar dalam ... dengan 2 standar keluar (tetapi Anda harus memodifikasi sumber untuk menetapkan "tot" ke ukuran file output yang diproyeksikan)

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.