Как добавить индикатор выполнения в оболочку script?

При написании сценария в bash или любой другой оболочке в * NIX при выполнении команды, которая займет больше нескольких секунд, требуется индикатор выполнения.

Например, копирование большого файла, открытие большого файла tar.

Какими способами вы рекомендуете добавлять индикаторы выполнения в сценарии оболочки?

+354
26 окт. '08 в 14:32
источник поделиться
36 ответов
  • 1
  • 2

Вы можете реализовать это, перезаписав строку. Используйте \r для возврата к началу строки, не записывая \n на терминал.

Запишите \n когда вы закончите линию.

Используйте echo -ne для:

  1. не печатать \n и
  2. распознавать escape-последовательности, такие как \r.

Вот демо:

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

В комментарии ниже, puk упоминает, что это "не удается", если вы начинаете с длинной строки, а затем хотите написать короткую строку: в этом случае вам нужно будет переписать длину длинной строки (например, пробелами).

+642
26 окт. '08 в 14:47
источник

Связанные вопросы


Похожие вопросы

Вы также можете быть заинтересованы в как сделать spinner:

Можно ли сделать счетчик в Bash?

Конечно!

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

Каждый раз, когда цикл повторяется, он отображает следующий символ в sp строка, обтекающая, когда она достигает конца. (i - позиция текущий символ для отображения и ${# sp} - длина sp строка).

Строка\b заменяется символом "backspace". С другой стороны, вы можете играть с \r, чтобы вернуться к началу строки.

Если вы хотите, чтобы он замедлялся, поставьте команду сна внутри цикла (после печати).

эквивалент POSIX:

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

Если у вас уже есть цикл, который выполняет большую работу, вы можете вызвать следующая функция в начале каждой итерации для обновления вертушка:

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
+58
25 июл. '10 в 20:12
источник

В некоторых сообщениях показано, как отобразить ход команды. Чтобы рассчитать его, вам нужно посмотреть, сколько вы продвинулись. В BSD-системах некоторые команды, такие как dd (1), принимают сигнал SIGINFO и сообщают о своем прогрессе. В системах Linux некоторые команды будут отвечать аналогично SIGUSR1. Если это средство доступно, вы можете отправить свой вход через dd, чтобы отслеживать количество обработанных байтов.

В качестве альтернативы вы можете использовать lsof, чтобы получить смещение указателя чтения файла и тем самым рассчитать прогресс. Я написал команду под названием pmonitor, которая отображает ход обработки указанного процесса или файла. С его помощью вы можете делать такие вещи, как, например, следующее.

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

Более ранняя версия сценариев оболочки Linux и FreeBSD появляется на в моем блоге.

+48
26 окт. '08 в 15:18
источник

используйте команду linux pv:

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

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

+38
28 июл. '11 в 17:35
источник

Получил простую функцию бара прогресса, которую я написал на днях:

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

Или поймать его,
https://github.com/fearside/ProgressBar/

+35
20 янв. '15 в 12:05
источник

Я искал что-то более сексуальное, чем выбранный ответ, так же как и мой собственный скрипт.

предварительный просмотр

progress-bar.sh in action

Источник

Я положил его на github progress-bar.sh -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
}

использование

 progress-bar 100
+22
06 окт. '16 в 14:17
источник

GNU tar имеет полезную опцию, которая дает функциональность простого индикатора выполнения.

(...) Еще одно доступное действие контрольной точки - "точка (или".). Он инструктирует tar печатать одну точку в стандартном потоке листинга, например:

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

Тот же эффект может быть получен:

$ tar -c --checkpoint=.1000 /var
+17
02 авг. '10 в 14:15
источник

Более простой метод, который работает в моей системе с помощью утилиты 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
+11
25 июл. '10 в 20:07
источник

Я также хотел бы внести свой собственный индикатор прогресса

Он достигает субактериальной точности, используя Half Unicode block

enter image description here

Код включен

+10
19 июл. '17 в 8:12
источник

Это позволяет вам визуализировать, что команда все еще выполняет:

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

Это создаст бесконечный цикл while, который выполняется в фоновом режиме и перекликается с символом ".". каждую секунду. Это отобразит . в оболочке. Запустите команду tar или любую команду, которую вы хотите. Когда эта команда завершает выполнение, тогда убить последнее задание, выполняемое в фоновом режиме - это бесконечный цикл while.

+6
02 мая '13 в 21:54
источник

Не видел ничего подобного... мое очень простое решение:

#!/bin/bash
BAR='####################'   # this is full bar, mine is 20 chars
for i in {1..20}; do
    echo -ne "\r${BAR:0:$i}" # print $i chars of $BAR from 0 position
    sleep .1
done
  • echo -n - печать без новой строки в конце
  • echo -e - интерпретировать специальные символы при печати
  • "\r" - возврат каретки, специальный char для возврата к началу строки

Я использовал его давно в простом "взломанном видео", чтобы имитировать код ввода.;)

+5
01 дек. '16 в 1:21
источник

Прежде всего, бар - это не единственный измеритель хода трубы. Другой (возможно, еще более известный) - pv (просмотрщик каналов).

Второй бар и pv можно использовать, например, следующим образом:

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

или даже:

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

один полезный трюк, если вы хотите использовать bar и pv в командах, которые работают с файлами, указанными в аргументах, например, например. copy file1 file2, использовать замещение процесса:

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

Подстановка процесса - это волшебная вещь bash, которая создает временные файлы файлов fifo/dev/fd/и соединяет stdout из запущенного процесса (внутри скобок) через этот канал, и копия видит его как обычный файл (за одним исключением, он может читать только вперед).

Update:

сама команда bar позволяет также копировать. После man bar:

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

Но замена процесса - это, на мой взгляд, более общий способ сделать это. Он сам использует программу cp.

+4
18 июл. '14 в 6:06
источник

В моем решении отображается процентный размер tarball, который в настоящее время несжатый и написанный. Я использую это при записи 2GB файлов корневой файловой системы. Вы действительно нужен индикатор прогресса для этих вещей. Я использую gzip --list, чтобы получить общий несжатый размер тарбол. Из этого я вычислил необходимый блокирующий фактор для деления файла на 100 частей. Наконец, я печатаю сообщение контрольной точки для каждого блока. Для 2-Гбайт файла это дает около 10 Мб блока. Если это слишком велико, вы можете разделите BLOCKING_FACTOR на 10 или 100, но тогда это сложнее распечатать довольно вывод в процентах.

Предполагая, что вы используете Bash, вы можете использовать следующая функция оболочки

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}
}
+4
24 авг. '10 в 9:01
источник

Большинство команд unix не дают вам прямой обратной связи, из которой вы можете это сделать. Некоторые будут давать вам вывод на stdout или stderr, которые вы можете использовать.

Для чего-то вроде tar вы можете использовать ключ -v и вывести вывод в программу, которая обновляет небольшую анимацию для каждой строки, которую она читает. Поскольку tar записывает список файлов, которые он распутывает, программа может обновлять анимацию. Чтобы выполнить процент, вам нужно знать количество файлов и подсчитывать строки.

cp не дает такого вывода, насколько я знаю. Чтобы отслеживать ход работы cp, вам необходимо будет контролировать исходный и целевой файлы и посмотреть размер адресата. Вы можете написать небольшую программу c, используя системный вызов stat (2), чтобы получить размер файла. Это будет читать размер источника, а затем опросить файл назначения и обновить строку% complete в зависимости от размера файла, записанного на сегодняшний день.

+3
26 окт. '08 в 14:42
источник

Я предпочитаю использовать диалог с параметром -gauge. Используется очень часто в установках пакета .deb и других базовых конфигурационных материалах многих дистрибутивов. Поэтому вам не нужно изобретать колесо... снова

Просто поместите значение int от 1 до 100 @stdin. Один простой и глупый пример:

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

У меня есть этот файл /bin/Wait (с chmod u + x perms) для приготовления пищи: 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"

Поэтому я могу поставить:

Wait "34 min" "warm up the oven"

или

Wait "dec 31" "happy new year"

+3
10 янв. '16 в 17:40
источник

Многие ответы описывают создание собственных команд для печати '\r' + $some_sort_of_progress_msg. Иногда проблема заключается в том, что распечатка сотен этих обновлений в секунду замедлит процесс.

Однако, если какой-либо из ваших процессов производит вывод (например, 7z a -r newZipFile myFolder выводит каждое имя файла по мере его сжатия), тогда существует более простое, быстрое, безболезненное и настраиваемое решение.

Установите модуль 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

Справка: tqdm -h. Пример использования дополнительных параметров:

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

В качестве бонуса вы также можете использовать tqdm для переноса итераций в код python.

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

+2
08 апр. '16 в 7:21
источник

для меня проще всего использовать и лучше всего смотреть на команду pv или bar, как какой-то парень уже писал

например: необходимо сделать резервную копию всего диска с помощью dd

обычно вы используете dd if="$input_drive_path" of="$output_file_path"

с pv вы можете сделать это следующим образом:

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

и прогресс идет непосредственно на STDOUT следующим образом:

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

после выполнения сводки появляется

    15654912+0 records in
    15654912+0 records out
    8015314944 bytes (8.0 GB) copied, 2020.49 s, 4.0 MB/s
+2
04 нояб. '14 в 13:02
источник

Основываясь на работе Эдуарда Лопеса, я создал индикатор выполнения, который соответствует размеру экрана, что бы это ни было. Проверьте это.

введите описание изображения здесь

Он также размещен на 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

Enjoy

+1
29 апр. '17 в 6:05
источник

Чтобы указать ход работы, попробуйте выполнить следующие команды:

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;

ИЛИ

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;

ИЛИ

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;

ИЛИ

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;

В цикле while можно использовать флаги/переменные, чтобы проверить и отобразить значение/степень прогресса.

+1
26 мая '15 в 9:04
источник

Индикатор выполнения в стиле APT (не нарушает нормальный вывод)

enter image description here

РЕДАКТИРОВАТЬ: Для получения обновленной версии проверьте мою страницу GitHub

Я не был удовлетворен ответами на этот вопрос. То, что я лично искал, было причудливым индикатором прогресса, как видит APT.

Я взглянул на исходный код C для APT и решил написать свой собственный эквивалент для bash.

Этот индикатор выполнения будет оставаться в нижней части терминала и не будет мешать любому выводу, отправленному на терминал.

Пожалуйста, обратите внимание, что в настоящее время панель имеет ширину 100 символов. Если вы хотите масштабировать его до размера терминала, это также довольно легко сделать (обновленная версия на моей странице github хорошо справляется с этим).

Я опубликую свой сценарий здесь. Пример использования:

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

Сценарий (я настоятельно рекомендую вместо этого версию на моем github):

#!/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}"
}
+1
04 дек. '18 в 15:49
источник

Я использовал ответ из создания строки повторяющихся символов в оболочке script для повторения char. У меня есть две относительно небольшие версии bash для скриптов, которые должны отображать индикатор выполнения (например, цикл, который проходит через множество файлов, но не полезен для больших файлов tar или операций копирования). Более быстрая состоит из двух функций: одна для подготовки строк для отображения на панели:

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

и один для отображения индикатора выполнения:

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
}

Его можно использовать как:

preparebar 50 "#"

что означает готовность строк для бара с символами 50 "#", а затем:

progressbar 35 80

отобразит число символов "#", соответствующее соотношению 35/80:

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

Помните, что функция отображает панель на одной и той же строке снова и снова, пока вы (или какая-либо другая программа) не напечатаете новую строку. Если вы поместите -1 в качестве первого параметра, панель будет стерта:

progressbar -1 80

Более медленная версия - все в одной функции:

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
}

и его можно использовать как (тот же пример, что и выше):

progressbar 35 80 50

Если вам нужен прогрессбар на stderr, просто добавьте >&2 в конец каждой команды printf.

+1
29 июн. '15 в 20:56
источник

Используя предложения, перечисленные выше, я решил реализовать свой собственный индикатор выполнения.

#!/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
22 янв. '18 в 20:05
источник

Это применимо только с помощью gnome zenity. Zenity предоставляет отличный интерфейс для скриптов bash: https://help.gnome.org/users/zenity/stable/

В примере с индикатором состояния Zenity:

#!/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
17 мар. '14 в 12:25
источник
#!/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;

выход:

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

примечание: если вместо 255 вы введете 1, вы будете контролировать стандарт на... с 2 на выходе стандарта (но вы должны изменить источник, чтобы установить "tot" в соответствии с прогнозируемым размером выходного файла)

0
11 дек. '18 в 8:41
источник

Вот как это могло бы выглядеть

Загрузка файла

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

Ожидание выполнения задания

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

Простая функция, которая ее реализует

Вы можете просто скопировать его в свой скрипт. Для работы не требуется ничего другого.

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

Пример использования

Здесь мы загружаем файл и перерисовываем индикатор выполнения на каждой итерации. Неважно, какая работа фактически выполняется, если мы можем получить 2 значения: максимальное значение и текущее значение.

В приведенном ниже примере максимальное значение - file_size и текущее значение предоставляется некоторой функцией и называется 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"
0
30 сент. '18 в 20:24
источник

Я основывался на ответе, предоставленном страхом

Это соединение с базой данных Oracle для восстановления хода восстановления 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
10 февр. '16 в 11:54
источник

https://github.com/extensionsapp/progre.sh

Создайте 40-процентный прогресс: progreSh 40

enter image description here

0
01 нояб. '18 в 2:04
источник
#!/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

}

может создать функцию, которая рисует это по шкале, скажем 1-10 для количества баров:

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
14 авг. '17 в 14:19
источник

Если вам нужно отобразить временной индикатор выполнения (зная заранее время показа), вы можете использовать Python следующим образом:

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

Затем, предположив, что вы сохранили Python script как progressbar.py, можно показать индикатор выполнения из bash script, выполнив следующую команду:

python progressbar.py 10 50

Отобразится индикатор выполнения, размер 50 и "работа" за 10 секунды.

0
27 мар. '15 в 9:45
источник

Я сделал чистую версию оболочки для встроенной системы, используя:

  • /usr/bin/dd Функция обработки сигналов SIGUSR1.

    В принципе, если вы отправите 'kill SIGUSR1 $(pid_of_running_dd_process)', он выведет краткую информацию о скорости и сумме пропускной способности.

  • backgrounding dd, а затем регулярно запрашивая его для обновлений и генерируя хеш-тики, например, используемые старыми клиентскими ftp-клиентами.

  • Использование/dev/stdout в качестве места назначения для дружественных программ, отличных от stdout, таких как scp

Конечный результат позволяет выполнить любую операцию передачи файлов и получить обновление выполнения, которое выглядит как выход хеширования старой школы FTP, где вы просто получите хэш-метку для каждого X байта.

Это вряд ли код качества продукции, но вы получаете эту идею. Я думаю, что это мило.

Для того, что стоит, фактический байт-счет не может быть правильно отражен в количестве хэшей - у вас может быть больше или меньше в зависимости от проблем округления. Не используйте это как часть теста script, это просто глазная конфета. И, да, я знаю, что это ужасно неэффективно - это оболочка script, и я не извиняюсь за нее.

Примеры с wget, scp и tftp приведены в конце. Он должен работать со всем, что испускает данные. Обязательно используйте /dev/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 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
}

Примеры:

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
0
10 окт. '14 в 1:03
источник
  • 1
  • 2

Посмотрите другие вопросы по меткам или Задайте вопрос