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

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

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

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

378
задан 12.01.2020, 05:52

36 ответов

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

656
ответ дан 12.01.2020, 05:53
  • 1
    Вопросом был " Как делают я действительно прогрессирую bars" с примером копирования файлов. Я сфокусировался на " graphics" проблема, не вычисление того, как далеко вдоль копии файла операция. – Mitch Haile 12.01.2020, 05:54
  • 2
    Я don' t получают это - принятый и "куча" upvotes для " I' ll предполагают, сколько времени эта операция возьмет неизвестный hardware" взлом? объем плазмы является корректным ответом IMO (но панель сделает также), – Stephen 12.01.2020, 05:54
  • 3
    Портативный способ произвести это состоит в том, чтобы использовать printf вместо echo. – Jens 12.01.2020, 05:55
  • 4
    для printf мы должны были бы использовать этот формат: printf "#### (50%%)\r", это wouldn' t работа с одинарными кавычками и знаком процента должен быть оставлен. – nurettin 12.01.2020, 05:55
  • 5
    Согласно эхо страница справочника (по крайней мере, на MacOS X) sh/bash используют свое собственное встроенное эхо команда это doesn' t принимают "-n"... поэтому для выполнения того же самого, необходимо поместить \r\c в конце строки, вместо всего \r – Justin Jenkins 12.01.2020, 05:55

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

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

enter image description here

2
ответ дан 12.01.2020, 05:54
  • 1
    Да you' право ре, эта ссылка описывает мою точную проблему. Я предполагаю, что в настоящее время нет никакого решения. Статья предполагает, что что-то было запланировано PHP6 для обращения к этому, но конечно that' s не собирающийся быть релевантным некоторое время. Спасибо за ссылку. – Wesley Murch 28.12.2019, 18:58

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

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

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

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

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

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

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

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

Примеры с 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 $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'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 $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
ответ дан 12.01.2020, 05:54
  • 1
    Используя ВИХРЕВУЮ командную строку: " завихритесь-X ПОМЕЩЕННЫЙ - заголовок " тип контента: application/octet-stream" - двоичный файл данных " @1.gif"-v/handler.php/bla/foo" и в файле PHP выводят содержание в файл. Это работает отлично. Однако я должен отправить некоторую дополнительную информацию, например, маркер с запросом для загрузки файла. Я думаю, что должен использовать POST. – vivek.m 07.05.2020, 06:04

Если вам нужно показать временную шкалу прогресса (заранее зная время показа), вы можете использовать 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 секунд.

0
ответ дан 12.01.2020, 05:55
  • 1
    Маркер может быть в заголовке также;) – Tomáš Fejfar 07.05.2020, 06:04
#!/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
ответ дан 12.01.2020, 05:56

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

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

enter image description here

Код включен

11
ответ дан 12.01.2020, 05:56

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

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

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

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

$ tar -c --checkpoint=.1000 /var
17
ответ дан 12.01.2020, 05:57

Более простой метод, который работает в моей системе с использованием утилиты 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
13
ответ дан 12.01.2020, 05:57

Чтобы создать индикатор выполнения tar

tar xzvf pippo.tgz |xargs -L 19 |xargs -I@ echo -n "."

Где «19» - это количество файлов в tar, разделенное на длину предполагаемого индикатора выполнения. Пример: .tgz содержит 140 файлов, и вам понадобится индикатор выполнения 76 ".", Вы можете поставить -L 2.

Вам больше ничего не нужно.

-2
ответ дан 12.01.2020, 05:58
  • 1
    Это характерно для tar, поэтому если сценарий оболочки только не состоит из tar команда, это doesn' t действительно относятся к OP' s случай. – doubleDown 12.01.2020, 05:59

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

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

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

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

8
ответ дан 12.01.2020, 05:59

Индикатор выполнения в стиле 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}"
}
4
ответ дан 12.01.2020, 06:00

У меня было то же самое сегодня, и, основываясь на ответе Диомидиса, вот как я это сделал (linux debian 6.0.7). Может быть, это могло бы помочь вам:

#!/bin/bash

echo "getting script inode"
inode=`ls -i ./script.sh | cut -d" " -f1`
echo $inode

echo "getting the script size"
size=`cat script.sh | wc -c`
echo $size

echo "executing script"
./script.sh &
pid=$!
echo "child pid = $pid"

while true; do
        let offset=`lsof -o0 -o -p $pid | grep $inode | awk -F" " '{print $7}' | cut -d"t" -f 2`
        let percent=100*$offset/$size
        echo -ne " $percent %\r"
done
-4
ответ дан 12.01.2020, 06:01
  • 1
    И, я получаю ошибку: progressbar: Zeile 17: let: offset=: Syntax Fehler: Operator erwartet. (Fehlerverursachendes Zeichen ist \"=\")., если я называю этот сценарий progressbar.sh и называю его с cd /tmp/; echo "sleep 5">script.sh; bash progressbar.sh на Ubuntu 13.04 – rubo77 12.01.2020, 06:01
  • 2
    Когда я запускаю этот сценарий как корень, я получаю ошибку: lsof: WARNING: can't stat() fuse.gvfsd-fuse file system /home/rubo77/.gvfs Output information may be incomplete. – rubo77 12.01.2020, 06:01
  • 3
    можете Вы объяснять, что смещает, вычисляют. – deven98602 12.01.2020, 06:02

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

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

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

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

Код:

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

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

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

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

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

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

-1
ответ дан 12.01.2020, 06:01
#!/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
ответ дан 12.01.2020, 06:01

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

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
ответ дан 12.01.2020, 06:02
  • 1
    Также никакое различие, спасибо за предложение. It' s добрался, чтобы быть чем-то, чтобы сделать с Windows или моей установкой PHP или обоими. I' m даже не уверенный это может быть зафиксировано с частью кода PHP... It' s становятся более низким приоритетом для меня на этой неделе, таким образом, я проведу еще некоторое исследование вовремя. – Wesley Murch 28.12.2019, 18:57

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

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: [110] [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

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

1
ответ дан 12.01.2020, 06:03

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

#!/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
ответ дан 12.01.2020, 06:03
  • 1
    Превосходный, большое спасибо! – Andreas Jansson 07.05.2020, 06:03

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

. Он соединяется с базой данных 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-

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

. Он соединяется с базой данных Oracle для получения информации о ходе восстановления RMAN.

[110]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
ответ дан 12.01.2020, 06:04
  • 1
    Этот doesn' t отвечают на вопрос. @AndreasJansson, что Вы изменяли для получения его работа? У меня есть та же проблема, и говорящий " Вы don' t уже должен сделать что-либо, это works" не ПОЛЕЗНО. – Benubird 07.05.2020, 06:05

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

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

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

Конечно, это будет приятно психоделический, хотя ...

#!/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=$1; local loca2=$2;
        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="$1"; local loca2="$2";
        loca=$(bc -l <<< scale=2\;"$loca/50")
        for i in {1..50}; do
                progressbar "$i" "$loca2";
                sleep "$loca";
        done
        printf "\n"
};
timeprogress "$1" "$2"
-1
ответ дан 12.01.2020, 06:04
  • 1
    Можно ли использовать теги кода? Это делает его намного более читаемым. – Styxxy 07.05.2020, 06:02

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

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

function bar {
  local items=$1
  local total=$2
  local size=$3
  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=$1
  printf " %${size}s  "
  echo -ne "\r"
}

function progress {
  local pid=$1
  local total=$2
  local file=$3

  bar 0 100 50
  while [[ "$(ps a | awk '{print $1}' | 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

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

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

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

Кстати: я использую bash на Mac OSX. Я основал этот код на счетчике из Мариасио .

-1
ответ дан 12.01.2020, 06:04
  • 1
    Он сказал, что хочет успокоительный API, таким образом, ему могут быть нечего делать с браузерами. Так или иначе текущая ПОМЕЩЕННАЯ поддержка браузеров, УДАЛИТЕ и т.д. через XmlHttpRequest – Artefacto 07.05.2020, 06:04

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

#!/bin/bash
# Updates the progress bar
# Parameters: 1. Percentage value
update_progress_bar()
{
  if [ $# -eq 1 ];
  then
    if [[ $1 == [0-9]* ]];
    then
      if [ $1 -ge 0 ];
      then
        if [ $1 -le 100 ];
        then
          local val=$1
          local max=100

          echo -n "["

          for j in $(seq $max);
          do
            if [ $j -lt $val ];
            then
              echo -n "="
            else
              if [ $j -eq $max ];
              then
                echo -n "]"
              else
                echo -n "."
              fi
            fi
          done

          echo -ne " "$val"%\r"

          if [ $val -eq $max ];
          then
            echo ""
          fi
        fi
      fi
    fi
  fi
}

update_progress_bar 0
# Further (time intensive) actions and progress bar updates
update_progress_bar 100
-3
ответ дан 12.01.2020, 06:05

Я использовал ответ из Создание строки повторяющихся символов в скрипте оболочки для повторения символов. У меня есть две относительно небольшие версии 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
ответ дан 12.01.2020, 06:06

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

Это применимо только с использованием гнома 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
ответ дан 12.01.2020, 06:07

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

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

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

41
ответ дан 12.01.2020, 06:08

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

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

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

[110]

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

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 /

36
ответ дан 12.01.2020, 06:09

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

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

progress-bar.sh in action

Источник

Я поместил его на github progress-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
25
ответ дан 12.01.2020, 06:09

Некоторые посты показали, как отображать прогресс команды. Чтобы рассчитать это, вам нужно увидеть, насколько вы продвинулись. В системах 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
ответ дан 12.01.2020, 06:10

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

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

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

4
ответ дан 12.01.2020, 06:11

Теги

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