Buat bilah progres di bash

13

Bagaimana saya bisa membuat progress bar dengan bash?

Ini skrip saya:

 #!/bin/bash
 pass='number1 number12 number13 number14 number15 number16'
 chk='number14'
 for i in $pass ; do
 if [ "$i" == "$chk" ]; then
 echo ' Found ^_^'
 else
 echo 'loading 50%'
 fi
 done

Saya ingin mengganti echo 'loading 50%'dengan apa pun untuk membuat bilah kemajuan.

Elang Hitam
sumber
1
Bilah progres di terminal atau bilah progres di jendela GUI yang terpisah?
Byte Commander
2
Di terminal
Black Hawk
The etamungkin melakukan apa yang Anda inginkan.
aioobe

Jawaban:

14

whiptail hadir dengan pra-instal di Ubuntu dan banyak distro lainnya, dan akan menampilkan elemen progres layar penuh (tapi masih berbasis terminal).

dialogadalah superset dari whiptail, jadi contoh ini akan bekerja sama baiknya dengan keduanya. Itu memang menyediakan elemen UI yang lebih maju, jadi mungkin berguna jika Anda mencari interaksi pengguna seperti pemetik file dan formulir, tetapi memiliki kelemahan tidak datang diinstal pada banyak sistem.

cambuk

dialog

for i in $(seq 1 100)
do
    sleep 0.1 
    echo $i
done | whiptail --title 'Test script' --gauge 'Running...' 6 60 0

Perhatikan bahwa output skrip ditafsirkan sebagai persentase, jadi Anda mungkin harus menyesuaikan output Anda sesuai.

Whiptail dan Dialog juga memungkinkan Anda untuk memodifikasi teks pada saat dijalankan melalui sintaksis yang agak samar:

phases=( 
    'Locating Jebediah Kerman...'
    'Motivating Kerbals...'
    'Treating Kessler Syndrome...'
    'Recruiting Kerbals...'
)   

for i in $(seq 1 100); do  
    sleep 0.1

    if [ $i -eq 100 ]; then
        echo -e "XXX\n100\nDone!\nXXX"
    elif [ $(($i % 25)) -eq 0 ]; then
        let "phase = $i / 25"
        echo -e "XXX\n$i\n${phases[phase]}\nXXX"
    else
        echo $i
    fi 
done | whiptail --title 'Kerbal Space Program' --gauge "${phases[0]}" 6 60 0

pvmenunjukkan progres file atau stream yang disalurkan melalui file tersebut. Namun itu tidak dapat (mudah?) Digunakan untuk menunjukkan kemajuan operasi kustom seperti loop. Ini dirancang khusus untuk streaming.

$ head -c 1G < /dev/urandom | pv -s 1G > /dev/null
 277MB 0:00:16 [17.4MB/s] [========>                           ] 27% ETA 0:00:43

Beberapa contoh dunia nyata pvsangat berguna:

# progress while importing a DB dump
pv mybigfile.sql | mysql -uroot -p dbname

# importing straight from a remote server
ssh user@server 'cat mybigfile.sql.gz' | pv | gzip -cd | mysql -uroot -p dbname

# taking a snapshot of a btrfs partition
btrfs send /snapshots/$date | pv | btrfs receive /mnt/backup/root

Saya tidak tahu ada perintah yang memberikan progress bar satu-baris dalam gaya pvatau wget, tetapi ada banyak skrip Bash / Perl / sed sederhana yang akan menambahkan fungsionalitas itu, seperti yang telah dibagikan orang lain di sini.

Mikkel
sumber
Untuk menunjukkan proses loop dengan pvAnda dapat membuatnya mencari output loop atau membuat beberapa output palsu, misalnya suatu echodi setiap iterasi, pipa itu ke pvdan berikan dengan iterasi hitungan -s. Jika tidak diinginkan, ingatlah untuk mengarahkan stdout loop ke /dev/null. Berikut ini contoh yang menunjukkan pendekatan ini .
hidangan penutup
6

Anda dapat menggunakan zenityuntuk membuat jendela dialog GTK sederhana. Salah satu opsi yang tersedia adalah dialog progress bar.

Anda membuat jendela seperti itu menggunakan zenity --progress. Agar bermanfaat, Anda harus menentukan lebih banyak informasi dengan menambahkan beberapa opsi di bawah ini (kutipan dari man zenity):

   Progress options
   --text=STRING
          Set the dialog text
   --percentage=INT
          Set initial percentage
   --auto-close
          Close dialog when 100% has been reached
   --auto-kill
          Kill parent process if cancel button is pressed
   --pulsate
          Pulsate progress bar
   --no-cancel
          Hides the cancel button

Ada dua mode:

  • berdenyut : Baris kemajuan berdenyut, itu hanya menunjukkan bahwa ada sesuatu yang sedang berjalan, tetapi tidak mengatakan apa-apa tentang kemajuan. Anda melakukan ini dengan mengatur --pulsatingopsi.

  • manual : Anda harus menyalurkan persentase kemajuan saat ini ke zenityinput standar perintah untuk memperbarui bilah kemajuan.
    Contoh untuk ini bisa terlihat seperti itu di bawah ini. Perhatikan bahwa perintah sebelumnya dikelompokkan ke subkulit sehingga semua output dialihkan ke zenitydialog dan bukan hanya dari perintah terakhir:

    (echo 10; sleep 2; echo 20; sleep 2; echo 50; sleep 2) | zenity --progress
Komandan Byte
sumber
Kalau-kalau ini juga akan menjadi pilihan.
Byte Commander
1
Maaf sayangku, ini adalah jendela progress bar GUI, saya ingin membuat progress bar di terminal, misalnya saya ingin melihatnya saat script sedang memeriksa ==>[ ###########--------------] 52%
Black Hawk
1
Ya saya mengerti. Hanya saja saya sudah menulis setengah dari jawaban saya ketika Anda mengatakan itu, jadi saya memutuskan untuk tetap mempostingnya kalau-kalau ada orang lain yang membutuhkannya di masa depan. Saya harap Anda tidak keberatan, karena ada beberapa solusi berbasis terminal juga.
Byte Commander
5

Kode ini akan melakukannya, dan tidak memerlukan apa pun (selain bash, tentu saja). Mencetak #tanda-tanda, seperti yang Anda tanyakan dalam komentar Anda:

pass='number1 number12 number13 number14 number15 number16'
chk='number14'
passarr=($pass)
lenProgressBar=${#passarr[@]}

echo -n '['
i=0

while [ $i -lt $lenProgressBar ]; do
    echo -n '-'
    ((i++))
done

echo -n ']'
i=0

while [ $i -lt $lenProgressBar ]; do
    echo -e -n '\b'
    ((i++))
done

echo -e -n '\b'
for i in $pass ; do
    if [ "$i" = "$chk" ]; then
        echo -e '#\nFound ^_^'
        break
    else
        echo -n '#'
    fi
done

Namun, jika Anda harus banyak memeriksa, ini hanya akan mengisi layar Anda dengan #tanda - tanda. Untuk memperbaiki masalah itu, coba kode ini:

lenProgressBar=5
pass='number1 number12 number13 number14 number15 number16'
chk='number14'
passarr=($pass)
lenPass=${#passarr[@]}

if [ $lenProgressBar -gt $lenPass ]; then
    lenProgressBar=lenPass
elif [ $lenProgressBar -lt 1 ]; then
    lenProgressBar=1
fi

let "chksForEqualsPrint = $lenPass / $lenProgressBar"
echo -n '['
i=0

while [ $i -lt $lenProgressBar ]; do
    echo -n '-'
    ((i++))
done

echo -n ']'
i=0

while [ $i -lt $lenProgressBar ]; do
    echo -e -n '\b'
    ((i++))
done

echo -e -n '\b'
n=1

for i in $pass ; do
    if [ "$i" = "$chk" ]; then
        echo -e '\nFound ^_^'
        break
    else
        if [ $n -eq $chksForEqualsPrint ]; then
            echo -n '#'
            n=1
        else
            ((n++))
        fi
    fi
done

Ubah 5 di baris pertama ( lenProgressBar=5) menjadi panjang yang Anda inginkan sebagai progress bar Anda. Diperlukan waktu lebih lama untuk mencetak #tanda dengan progress bar yang lebih rendah daripada yang panjangnya lebih tinggi, tetapi jangan biarkan panjang progress bar melebihi ukuran layar Anda; itu tidak akan bekerja dengan baik jika Anda melakukannya. (Ini tidak akan membiarkan Anda menggunakan bilah kemajuan lebih tinggi dari jumlah item yang Anda periksa atau lebih rendah dari 1)

masukkan_name_di sini
sumber
1
Anda bisa menggunakan tput colsuntuk mendeteksi lebar jendela terminal dan skala progressbar yang sesuai.
Mikkel
1

Berikut pendekatan lain menggunakan kode pelarian ansi:

#!/bin/bash

pass='number1 number2 number 3 number4 number12 number13 number14 number15 number16'
chk='number15'
result="Not Found!"

echo
echo -n "Working... "
echo -ne "\033[1;32m\033[7m\033[?25l"

for i in $pass ; do
   sleep .4s
   if [ "$i" == "$chk" ]; then
      result="  Found ^_^"
      break
   else
      echo -n " "
   fi
done

echo -ne "\r\033[0m\033[K\033[?25h"
echo $result
echo
bashBedlam
sumber