Как добавить индикатор в скрипт?

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

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

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

30 ответов


вы можете реализовать это путем перезаписи линии. Использовать \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 упоминает об этом "не удается", если вы начинаете с длинной строкой, а затем хотите написать короткую строку: в этом случае вам нужно будет перезаписать длину длинной строки (например, пробелами).


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

могу ли я сделать спиннер в Bash?

точно!

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

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

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

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

эквивалент POSIX будет:

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

Если у вас уже есть цикл, который делает много работы, вы можете позвонить следующая функция в начале каждой итерации для обновления 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

некоторые сообщения показали, как отображать прогресс команды. Чтобы рассчитать его, вам нужно будет увидеть, насколько вы продвинулись. В системах 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 появляется на мой блог.


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

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

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


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

#!/bin/bash
# 1. Create ProgressBar function
# 1.1 Input is currentState() and totalState()
function ProgressBar {
# Process data
    let _progress=(*100/*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/


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

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

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

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

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

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

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

progress-bar.sh in action

источник

Я надел его github progress-bar.sh

progress-bar() {
  local duration=


    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

более простой метод, который работает в моей системе с помощью утилиты pipeview ( pv).

srcdir=
outfile=


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

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

Он достигает суб-символ точности, используя половина блоков Юникода

enter image description here

кода


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

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 command или любая команда, которую вы хотите. Когда эта команда завершит выполнение, то убить последнее задание выполняется в фоновом режиме-это бесконечный цикл while.


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

#!/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" - возврат каретки, специальный символ для возврата в начало строки

я использовал его давным-давно в простом "взломе видео" для имитации ввода кода. ;)


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

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

untar_progress () 
{ 
  TARBALL=
  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}
}

прежде всего бар не только один метр прогресса трубы. Другой (возможно, даже более известный) - PV (Pipe viewer).

Secondly адвокатское сословие и 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

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

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

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


Я предпочитаю использовать


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

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

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 для проверки и отображения значения/степень прогресса.


многие ответы описывают написание собственных команд для распечатки '\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


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

enter image description here

Он также размещен на 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:  [SECONDS]"
  case  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
[[  =~ ^[0-9]+$ ]] || error 2

duration=
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

наслаждайтесь


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

#!/usr/bin/env bash

main() {
  for (( i = 0; i <= 100; i=$i + 20)); do
    progress_bar "$i"
    sleep 1;
  done
  progress_bar "done"
  exit 0
}

progress_bar() {
  if [ "" == "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 "$@"

это применимо только с помощью 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

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

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

и один для отображения прогресса бар:

progressbar() {
#  - number (-1 for clearing the bar)
#  - max number
    if [  -eq -1 ]; then
        printf "\r  $barspaces\r"
    else
        barch=$((*barlen/))
        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() {
#  - number
#  - max number
#  - number of '#' characters
    if [  -eq -1 ]; then
        printf "\r  %*s\r" ""
    else
        i=$((*/))
        j=$((-i))
        printf "\r[%*s" "$i" | tr ' ' '#'
        printf "%*s]\r" "$j"
    fi
}

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

progressbar 35 80 50

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


#!/bin/bash

function progress_bar() {
    bar=""
    total=10
    [[ -z  ]] && input=0 || input=
    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

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

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

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

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

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

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

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

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

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

        # 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

если вам нужно показать временной индикатор выполнения (заранее зная время показа), вы можете использовать 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, как progressbar.py, можно показать индикатор выполнения из сценария bash, выполнив следующую команду:

python progressbar.py 10 50

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


Я построил на ответе, предоставленном fearside

это подключается к базе данных Oracle для получения прогресса восстановления RMAN.

#!/bin/bash

 # 1. Create ProgressBar function
 # 1.1 Input is currentState() and totalState()
 function ProgressBar {
 # Process data
let _progress=(*100/*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'

это психоделический progressbar для сценариев bash от nExace. Его можно вызвать из командной строки как './ progressbar x y', где " x "- время в секундах, а " y " - сообщение, связанное с этой частью прогресса.

внутренняя функция progressbar () также хороша автономно, если вы хотите, чтобы другие части вашего скрипта контролировали progressbar. Например, отправка "progressbar 10" создание дерева каталогов"; " отобразит:

[#######                                     ] (10%) Creating directory tree

Of конечно, это будет хороший психоделический эффект...

#!/bin/bash

if [ "$#" -eq 0 ]; then echo "x is \"time in seconds\" and z is \"message\""; echo "Usage: progressbar x z"; exit; fi
progressbar() {
        local loca=; local loca2=;
        declare -a bgcolors; declare -a fgcolors;
        for i in {40..46} {100..106}; do
                bgcolors+=("$i")
        done
        for i in {30..36} {90..96}; do
                fgcolors+=("$i")
        done
        local u=$(( 50 - loca ));
        local y; local t;
        local z; z=$(printf '%*s' "$u");
        local w=$(( loca * 2 ));
        local bouncer=".oO°Oo.";
        for ((i=0;i<loca;i++)); do
                t="${bouncer:((i%${#bouncer})):1}"
                bgcolor="\E[${bgcolors[RANDOM % 14]}m \033[m"
                y+="$bgcolor";
        done
        fgcolor="\E[${fgcolors[RANDOM % 14]}m"
        echo -ne " $fgcolor$t$y$z$fgcolor$t \E[96m(\E[36m$w%\E[96m)\E[92m $fgcolor$loca2\033[m\r"
};
timeprogress() {
        local loca=""; local loca2="";
        loca=$(bc -l <<< scale=2\;"$loca/50")
        for i in {1..50}; do
                progressbar "$i" "$loca2";
                sleep "$loca";
        done
        printf "\n"
};
timeprogress "" ""

сначала выполните процесс в фоновом режиме, затем посмотрите, как он часто работает, который запускал печать шаблона и снова проверьте, работает ли он или нет;

использование цикла while для частого просмотра состояния процесса.

используйте pgrep или любую другую команду для просмотра и получения состояния процесса.

при использовании pgrep перенаправьте ненужный вывод в /dev / null как необходимый.

код:

sleep 12&
while pgrep sleep &> /dev/null;do echo -en "#";sleep 0.5;done

этот " # " будет печататься до завершения сна,этот метод используется для реализации индикатора выполнения Для времени выполнения программы.

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

ошибка: этот метод pgrep не работает во всех ситуациях,неожиданно другой процесс выполняется с тем же именем, цикл while не работает конец.

поэтому получение процесс идущее состояние указывать это ПИД, используя пусть процесс может быть доступен с некоторыми командами,

команда П. С. перечислит весь процесс с id, вам нужно grep чтобы узнать pid указанного процесса


Я хотел отслеживать прогресс на основе количества строк вывода команды против целевого количества строк из предыдущего запуска:

#!/bin/bash
function lines {
  local file=
  local default=
  if [[ -f $file ]]; then
    wc -l $file | awk '{print }';
  else
    echo $default
  fi
}

function bar {
  local items=
  local total=
  local size=
  percent=$(($items*$size/$total % $size))
  left=$(($size-$percent))
  chars=$(local s=$(printf "%${percent}s"); echo "${s// /=}")
  echo -ne "[$chars>";
  printf "%${left}s"
  echo -ne ']\r'
}

function clearbar {
  local size=
  printf " %${size}s  "
  echo -ne "\r"
}

function progress {
  local pid=
  local total=
  local file=

  bar 0 100 50
  while [[ "$(ps a | awk '{print }' | grep $pid)" ]]; do
    bar $(lines $file 0) $total 50
    sleep 1
  done
  clearbar 50
  wait $pid
  return $?
}

тогда используйте его так:

target=$(lines build.log 1000)
(mvn clean install > build.log 2>&1) &
progress $! $target build.log

он выводит индикатор выполнения, который выглядит примерно так:

[===============================================>   ]

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

BTW: я использую bash на Mac OSX. Я основал этот код на spinner от mariascio.


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

Загрузить файл

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

ожидание завершения работы

[#########################                         ] 100% (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=
  local __max=
  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"