Создать индикатор выполнения в Bash

Как я могу создать индикатор выполнения с помощью 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%' с чем угодно, чтобы создать индикатор выполнения.

5 ответов

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 и Dialog также позволяют вам изменять текст во время выполнения с помощью довольно загадочного синтаксиса:

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, которые добавят эту функциональность, как и другие здесь поделились.

Ты можешь использовать 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
    

Этот код сделает это, и не требует ничего (кроме 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)

Вот еще один подход с использованием escape-кодов 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

Из переполнения стека

Мне нужен был индикатор выполнения, который помещался бы во всплывающем сообщении () для представления уровня громкости телевизора. Недавно я писал музыкальный проигрыватель на питоне, и большую часть времени изображение с телевизора отключалось.

Пример вывода из терминала


Баш-скрипт

      #!/bin/bash

# Show a progress bar at step number $1 (from 0 to 100)


function is_int() { test "$@" -eq "$@" 2> /dev/null; } 

# Parameter 1 must be integer
if ! is_int "$1" ; then
   echo "Not an integer: ${1}"
   exit 1
fi

# Parameter 1 must be >= 0 and <= 100
if [ "$1" -ge 0 ] && [ "$1" -le 100 ]  2>/dev/null
then
    :
else
    echo bad volume: ${1}
    exit 1
fi

# Main function designed for quickly copying to another program 
Main () {

    Bar=""                      # Progress Bar / Volume level
    Len=25                      # Length of Progress Bar / Volume level
    Div=4                       # Divisor into Volume for # of blocks
    Fill="▒"                    # Fill up to $Len
    Arr=( "▉" "▎" "▌" "▊" )     # UTF-8 left blocks: 7/8, 1/4, 1/2, 3/4

    FullBlock=$((${1} / Div))   # Number of full blocks
    PartBlock=$((${1} % Div))   # Size of partial block (array index)

    while [[ $FullBlock -gt 0 ]]; do
        Bar="$Bar${Arr[0]}"     # Add 1 full block into Progress Bar
        (( FullBlock-- ))       # Decrement full blocks counter
    done

    # If remainder zero no partial block, else append character from array
    if [[ $PartBlock -gt 0 ]]; then
        Bar="$Bar${Arr[$PartBlock]}"
    fi

    while [[ "${#Bar}" -lt "$Len" ]]; do
        Bar="$Bar$Fill"         # Pad Progress Bar with fill character
    done

    echo Volume: "$1 $Bar"
    exit 0                      # Remove this line when copying into program
} # Main

Main "$@"

Тестовый bash-скрипт

Используйте этот скрипт для проверки индикатора выполнения в терминале.

      #!/bin/bash

# test_progress_bar3

Main () {

    tput civis                              # Turn off cursor
    for ((i=0; i<=100; i++)); do
        CurrLevel=$(./progress_bar3 "$i")   # Generate progress bar 0 to 100
        echo -ne "$CurrLevel"\\r            # Reprint overtop same line
        sleep .04
    done
    echo -e \\n                             # Advance line to keep last progress
    echo "$0 Done"
    tput cnorm                              # Turn cursor back on
} # Main

Main "$@"

TL;DR

В этом разделе подробно описано, как используется для быстрого спама всплывающих сообщений на рабочем столе. Это необходимо, поскольку уровень громкости может меняться много раз в секунду, а поведение пузырькового сообщения по умолчанию заключается в том, что сообщение остается на рабочем столе в течение многих секунд.

Пример всплывающего всплывающего сообщения

Bash-код всплывающего всплывающего сообщения

Из скрипта выше функция была скопирована в новый функционал с именем VolumeBarв существующем сценарии bash, называемом tvpowered. exit 0команда в скопированном mainфункция была удалена.

Вот как это вызвать и сообщить команде Ubuntu, что мы будем рассылать спам всплывающим сообщением:

      VolumeBar $CurrVolume
# Ask Ubuntu: https://askubuntu.com/a/871207/307523
notify-send --urgency=critical "tvpowered" \
    -h string:x-canonical-private-synchronous:volume \
    --icon=/usr/share/icons/gnome/48x48/devices/audio-speakers.png \
    "Volume: $CurrVolume $Bar"

Это новая строка, которая говорит notify-sendчтобы немедленно заменить последний всплывающий пузырь:

      -h string:x-canonical-private-synchronous:volume \

группирует всплывающие сообщения вместе, и новые сообщения в этой группе немедленно заменяют предыдущие. Вы можете использовать anythingвместо volume.

Другие вопросы по тегам