Вышеупомянутые примечания верны, но имейте в виду, что пользователь может заставить свой браузер не отправлять эту информацию, или они могут связываться с этой информацией и отправлять ложные данные.
Вы можете реализовать это, переписав строку. Используйте \r
, чтобы вернуться к началу строки, не записывая \n
в терминал.
Напишите \n
, когда закончите продвигать линию.
Используйте echo -ne
, чтобы:
\n
и \r
. Вот демо:
echo -ne '##### (33%)\r'
sleep 1
echo -ne '############# (66%)\r'
sleep 1
echo -ne '####################### (100%)\r'
echo -ne '\n'
В комментарии ниже, puk упоминает, что это «не получается», если вы начинаете с длинной строки, а затем хотите написать короткую строку: в этом случае, вам нужно будет перезаписать длину длинной строки (например, пробелами).
Чтобы указать ход выполнения действий, попробуйте следующие команды:
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 для проверки и отображения значения / степени прогресса.
Используя предложения, перечисленные выше, я решил реализовать свой собственный индикатор выполнения.
#!/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 "$@"
Основываясь на работе Эдуарда Лопеса, я создал индикатор выполнения, который соответствует размеру экрана, каким бы он ни был. Проверьте это.
Он также размещен на 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
Наслаждайтесь
Если вам нужно показать временную шкалу прогресса (заранее зная время показа), вы можете использовать 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
секунд.
#!/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
Я сделал чисто версию оболочки для встроенной системы, используя преимущества:
/ 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
У меня было то же самое сегодня, и, основываясь на ответе Диомидиса, вот как я это сделал (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
Я также хотел бы добавить свой собственный индикатор выполнения
Он достигает точности субсимволов, используя половину блоков Unicode
Код включен
Я искал что-то более сексуальное, чем выбранный ответ, как и мой собственный сценарий.
Я поместил его на 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
Однажды у меня также был занят сценарий, который был занят часами, не показывая никакого прогресса. Поэтому я реализовал функцию, которая в основном включает в себя приемы предыдущих ответов:
#!/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
используйте команду linux pv:
, если размер неизвестен, он находится в середине потока, но он дает скорость и общее количество, и оттуда вы можете выяснить, сколько времени это займет, и получить обратную связь, чтобы вы знали, что он не завис.
Более простой метод, который работает в моей системе с использованием утилиты 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
Это применимо только с использованием гнома 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
Прежде всего, это не единственный индикатор хода трубы. Другой (может быть, даже более известный) - это pv (pipe viewer).
Во-вторых, bar и pv можно использовать, например, так:
$ bar file1 | wc -l
$ pv file1 | wc -l
или даже:
$ tail -n 100 file1 | bar | wc -l
$ tail -n 100 file1 | pv | wc -l
один полезный трюк, если вы хотите использовать бар и pv в командах, которые работают с файлами, указанными в аргументах, например, например copy file1 file2, должен использовать подстановка процесса :
$ copy <(bar file1) file2
$ copy <(pv file1) file2
Подстановка процесса - это волшебная вещь bash, которая создает временные файлы fifo pipe / dev / fd / и подключает стандартный вывод из запущенного процесса ( в круглых скобках) через этот канал, и копия видит его как обычный файл (за одним исключением, он может только читать его вперед).
Обновление:
сама команда bar также позволяет копировать. После man bar:
bar --in-file /dev/rmt/1cbn --out-file \
tape-restore.tar --size 2.4g --buffer-size 64k
Но замена процесса - это, на мой взгляд, более общий способ сделать это. Он использует саму программу cp.
Многие ответы описывают написание ваших собственных команд для распечатки '\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.
Большинство команд Unix не даст вам прямой обратной связи, из которой вы можете сделать это. Некоторые дадут вам вывод на стандартный вывод или стандартный вывод, который вы можете использовать.
Для чего-то вроде tar вы можете использовать ключ -v и направить вывод в программу, которая обновляет небольшую анимацию для каждой строки, которую она читает. Когда tar записывает список файлов, которые он распаковывает, программа может обновить анимацию. Чтобы выполнить процент выполнения, вам нужно знать количество файлов и считать строки.
cp не дает такой вывод, насколько я знаю. Чтобы отслеживать прогресс cp, вам нужно будет отслеживать исходные и конечные файлы и следить за размером получателя. Вы можете написать небольшую программу на c, используя системный вызов stat (2) , чтобы получить размер файла. Это будет считывать размер источника, затем опрашивать файл назначения и обновлять панель% complete в зависимости от размера файла, записанного на сегодняшний день.
Вы также можете быть заинтересованы в , как сделать прядильщик :
Конечно!
i=1 sp="/-\|" echo -n ' ' while true do printf "\b${sp:i++%${#sp}:1}" done
Каждый раз, когда цикл повторяется, он отображает следующий символ в строке sp, оборачиваясь по мере достижения конца. (i - позиция отображаемого текущего символа, а $ {# sp} - длина строки sp).
Строка \ b заменяется символом «возврат». Или вы можете поиграть с \ r, чтобы вернуться к началу строки.
Если вы хотите, чтобы это замедлилось, поместите команду сна в цикл (после printf).
Эквивалентом 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
Я хотел отследить прогресс, основываясь на количестве строк, которые выводила команда, против целевого числа строк из предыдущего запуска:
#!/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. Я основал этот код на счетчике из Мариасио .
Это позволяет визуализировать, что команда все еще выполняется:
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 .
Я использовал ответ из Создание строки повторяющихся символов в скрипте оболочки для повторения символов. У меня есть две относительно небольшие версии 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.
GNU tar имеет полезную опцию, которая дает функциональность простого индикатора выполнения.
(...) Другое доступное действие контрольной точки - «точка» (или «.»). Он указывает tar печатать одну точку в стандартном потоке листинга, например :
$ tar -c --checkpoint=1000 --checkpoint-action=dot /var
...
Тот же эффект может быть получен с помощью:
$ tar -c --checkpoint=.1000 /var
РЕДАКТИРОВАТЬ: Для получения обновленной версии проверьте мой 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}"
}
Мое решение отображает процентную долю архива, который в данный момент распаковывается и записывается. Я использую это, когда записываю образы корневой файловой системы 2 ГБ. Вам действительно нужен индикатор прогресса для этих вещей. Я использую 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}
}
Это психоделический индикатор прогресса для 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"
для меня проще всего пользоваться и лучше всего выглядеть до сих пор - это команда 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
Некоторые посты показали, как отображать прогресс команды. Чтобы рассчитать это, вам нужно увидеть, насколько вы продвинулись. В системах 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 появилась в моем блоге .
Загрузка файла
[##################################################] 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 (( Вот как это может выглядеть
Загрузка файла
[110] Ожидание завершения задания
[111] Простая функция, которая ее реализует
Вы можете просто скопировать и вставить ее в свой скрипт. Больше ничего не требуется для работы.
[112] Пример использования
Здесь мы загружаем файл и перерисовываем индикатор выполнения на каждой итерации. Неважно, какое задание фактически выполняется, если мы можем получить 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"
_max < 1 )); then __max=1; fi # anti zero division protection
local __percentage=$(( 100 - ( Вот как это может выглядеть
Загрузка файла
[110] Ожидание завершения задания
[111] Простая функция, которая ее реализует
Вы можете просто скопировать и вставить ее в свой скрипт. Больше ничего не требуется для работы.
[112] Пример использования
Здесь мы загружаем файл и перерисовываем индикатор выполнения на каждой итерации. Неважно, какое задание фактически выполняется, если мы можем получить 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"
_max*100 - Вот как это может выглядеть
Загрузка файла
[110] Ожидание завершения задания
[111] Простая функция, которая ее реализует
Вы можете просто скопировать и вставить ее в свой скрипт. Больше ничего не требуется для работы.
[112] Пример использования
Здесь мы загружаем файл и перерисовываем индикатор выполнения на каждой итерации. Неважно, какое задание фактически выполняется, если мы можем получить 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"
_value*100) / Вот как это может выглядеть
Загрузка файла
[110] Ожидание завершения задания
[111] Простая функция, которая ее реализует
Вы можете просто скопировать и вставить ее в свой скрипт. Больше ничего не требуется для работы.
[112] Пример использования
Здесь мы загружаем файл и перерисовываем индикатор выполнения на каждой итерации. Неважно, какое задание фактически выполняется, если мы можем получить 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"
_max ))
# Rescale the bar according to the progress bar width
local __num_bar=$(( Вот как это может выглядеть
Загрузка файла
[110] Ожидание завершения задания
[111] Простая функция, которая ее реализует
Вы можете просто скопировать и вставить ее в свой скрипт. Больше ничего не требуется для работы.
[112] Пример использования
Здесь мы загружаем файл и перерисовываем индикатор выполнения на каждой итерации. Неважно, какое задание фактически выполняется, если мы можем получить 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"
_percentage * $PROGRESS_BAR_WIDTH / 100 ))
# Draw progress bar
printf "["
for b in $(seq 1 Вот как это может выглядеть
Загрузка файла
[110] Ожидание завершения задания
[111] Простая функция, которая ее реализует
Вы можете просто скопировать и вставить ее в свой скрипт. Больше ничего не требуется для работы.
[112] Пример использования
Здесь мы загружаем файл и перерисовываем индикатор выполнения на каждой итерации. Неважно, какое задание фактически выполняется, если мы можем получить 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"
_num_bar); do printf "#"; done
for s in $(seq 1 $(( $PROGRESS_BAR_WIDTH - Вот как это может выглядеть
Загрузка файла
[110] Ожидание завершения задания
[111] Простая функция, которая ее реализует
Вы можете просто скопировать и вставить ее в свой скрипт. Больше ничего не требуется для работы.
[112] Пример использования
Здесь мы загружаем файл и перерисовываем индикатор выполнения на каждой итерации. Неважно, какое задание фактически выполняется, если мы можем получить 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"
_num_bar ))); do printf " "; done
printf "] Вот как это может выглядеть
Загрузка файла
[110] Ожидание завершения задания
[111] Простая функция, которая ее реализует
Вы можете просто скопировать и вставить ее в свой скрипт. Больше ничего не требуется для работы.
[112] Пример использования
Здесь мы загружаем файл и перерисовываем индикатор выполнения на каждой итерации. Неважно, какое задание фактически выполняется, если мы можем получить 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"
_percentage%% ( Вот как это может выглядеть
Загрузка файла
[110] Ожидание завершения задания
[111] Простая функция, которая ее реализует
Вы можете просто скопировать и вставить ее в свой скрипт. Больше ничего не требуется для работы.
[112] Пример использования
Здесь мы загружаем файл и перерисовываем индикатор выполнения на каждой итерации. Неважно, какое задание фактически выполняется, если мы можем получить 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"
_value / Вот как это может выглядеть
Загрузка файла
[110] Ожидание завершения задания
[111] Простая функция, которая ее реализует
Вы можете просто скопировать и вставить ее в свой скрипт. Больше ничего не требуется для работы.
[112] Пример использования
Здесь мы загружаем файл и перерисовываем индикатор выполнения на каждой итерации. Неважно, какое задание фактически выполняется, если мы можем получить 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"
_max Вот как это может выглядеть
Загрузка файла
[110] Ожидание завершения задания
[111] Простая функция, которая ее реализует
Вы можете просто скопировать и вставить ее в свой скрипт. Больше ничего не требуется для работы.
[112] Пример использования
Здесь мы загружаем файл и перерисовываем индикатор выполнения на каждой итерации. Неважно, какое задание фактически выполняется, если мы можем получить 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"
_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"
Ничего подобного не видел, так что ... мое очень простое решение:
#!/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"
- возврат каретки, специальный символ для возврата в начало строки Я использовал его давным-давно в простом «взломе» видео "для имитации набора текста. ;)