Створіть панель прогресу в bash


14

Як я можу створити панель прогресу за допомогою bash?

Це мій сценарій:

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

Я хочу замінити echo 'loading 50%'чим-небудь, щоб створити панель прогресу.


1
Рядок прогресу в терміналі або смуга прогресу в окремому вікні графічного інтерфейсу?
Командир байт

2
У терміналі
Black Hawk

etaМоже робити те , що ви хочете.
aioobe

Відповіді:


14

whiptail поставляється з попередньо встановленою програмою Ubuntu та багатьма іншими дистрибутивами та показуватиме елементи прогресу на весь екран (але все ще на терміналі).

dialogє супернабір whiptail, тому цей приклад буде однаково добре працювати з обома. Він надає більш вдосконалені елементи інтерфейсу, тому може стати в нагоді, якщо ви шукаєте взаємодію з користувачами, такими як інструменти для вибору файлів та форм, але це недолік, якщо він не встановлюється заздалегідь у багатьох системах.

батог

діалог

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

Зверніть увагу, що вихід сценарію інтерпретується у відсотках, тому вам, можливо, доведеться відповідним чином відрегулювати результат.

Whiptail і діалог також дозволяють змінювати текст під час виконання за допомогою досить криптованого синтаксису:

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

pvпоказує хід файлу або потоку, який проходить через нього. Однак його не можна (легко?) Використовувати для показу прогресу користувацької операції, такої як цикл. Він створений спеціально для потоків.

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

Деякі приклади реального світу, де це pvстане в нагоді:

# 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

Я не знаю жодної команди, яка дає однорядкові смуги прогресу в стилі pvабо wget, але є безліч простих сценаріїв Bash / Perl / sed, які додадуть цю функціональність, як тут поділилися інші.


Щоб показати процес циклу, pvви можете або змусити його шукати висновок циклу, або створити якийсь фальшивий вихід, наприклад, під час echoкожної ітерації, pvпередати його та надати йому кількість ітерацій -s. Якщо цього не потрібно, пам’ятайте, що слід перенаправити штрих циклу на /dev/null. Ось приклад, що показує такий підхід .
десерт

6

Ви можете використовувати zenityдля створення простих діалогових вікон GTK. Один із доступних варіантів - діалогове вікно діапазону прогресу.

Таке вікно ви створюєте, використовуючи zenity --progress. Щоб зробити його корисним, вам слід вказати додаткову інформацію, додавши деякі варіанти нижче (уривок з 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

Є два режими:

  • пульсуюча : Панель прогресу пульсує, вона просто вказує, що щось працює, але нічого не говорить про прогрес. Ви робите це, встановлюючи --pulsatingпараметр.

  • посібник : Вам потрібно передавати поточний відсоток прогресу на zenityстандартний вхід команди, щоб оновити панель виконання.
    Приклад для цього може виглядати нижче. Зауважте, що попередні команди згруповані в підклітинку, так що весь вихід буде переспрямований до zenityдіалогового вікна, а не лише до останньої команди:

    (echo 10; sleep 2; echo 20; sleep 2; echo 50; sleep 2) | zenity --progress

Про всяк випадок це також було б варіантом.
Байт-командир

1
Вибачте, мій дорогий, це вікна панелі прогресу GUI, я хочу створити панель прогресу в терміналі, наприклад, я хочу його бачити, поки перевіряється сценарій ==>[ ###########--------------] 52%
Black Hawk

1
Так я розумію. Просто я вже написав половину своєї відповіді, коли ви це сказали, тому я просто вирішив все-таки опублікувати її, якщо у майбутньому це може знадобитися комусь іншому. Сподіваюсь, ви не заперечуєте, оскільки існує також досить багато рішень на базі терміналів.
Командир байт

5

Цей код зробить це, і нічого не вимагає (крім, звичайно, bash). Він друкує #знаки, як ви запитали у своєму коментарі:

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

Однак якщо вам доведеться багато перевірити, це просто заповнить ваш екран #знаками. Щоб виправити цю проблему, спробуйте цей код:

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

Змініть 5 у першому рядку ( lenProgressBar=5) на довжину, якою ви хочете бути у вашій смузі прогресу. На друк #знака знадобиться більше пробілів пробігу меншої довжини, ніж з більш високими, але не дозволяйте довжині смуги прогресу перевищувати розмір екрана; це не спрацює добре, якщо ви зробите це. (Це не дозволить вам використовувати панель прогресу вище, ніж кількість елементів, які ви перевіряєте, або нижче 1)


1
Ви можете використовувати tput colsдля визначення ширини вікна терміналу та відповідно масштабування панелі прогресу.
Міккель

1

Ось ще один підхід із використанням кодів втечі 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.