Используя bash только script, как вы можете указать индикатор прогресса bash?
Итак, я могу запустить командную форму bash, и пока эта команда выполняется, пусть пользователь знает, что что-то еще происходит.
Используя bash только script, как вы можете указать индикатор прогресса bash?
Итак, я могу запустить командную форму bash, и пока эта команда выполняется, пусть пользователь знает, что что-то еще происходит.
В этом примере, используя SCP, я демонстрирую, как захватить идентификатор процесса (pid), а затем сделать что-то, пока этот процесс запущен.
Отображает простую иконку spinnng.
/usr/bin/scp [email protected]:file somewhere 2>/dev/null &
pid=$! # Process Id of the previous running command
spin[0]="-"
spin[1]="\\"
spin[2]="|"
spin[3]="/"
echo -n "[copying] ${spin[0]}"
while [ kill -0 $pid ]
do
for i in "${spin[@]}"
do
echo -ne "\b$i"
sleep 0.1
done
done
Решение Уильяма Пурселла
/usr/bin/scp [email protected]:file somewhere 2>/dev/null &
pid=$! # Process Id of the previous running command
spin='-\|/'
i=0
while kill -0 $pid 2>/dev/null
do
i=$(( (i+1) %4 ))
printf "\r${spin:$i:1}"
sleep .1
done
Если у вас есть способ оценить процентное количество, например текущее количество обработанных файлов и общее количество, вы можете сделать простой линейный счетчик хода с небольшой математикой и предположениями о ширине экрана.
count=0
total=34
pstr="[=======================================================================]"
while [ $count -lt $total ]; do
sleep 0.5 # this is work
count=$(( $count + 1 ))
pd=$(( $count * 73 / $total ))
printf "\r%3d.%1d%% %.${pd}s" $(( $count * 100 / $total )) $(( ($count * 1000 / $total) % 10 )) $pstr
done
Или вместо линейного счетчика вы можете оценить оставшееся время. Это примерно так же точно, как и другие подобные вещи.
count=0
total=34
start=`date +%s`
while [ $count -lt $total ]; do
sleep 0.5 # this is work
cur=`date +%s`
count=$(( $count + 1 ))
pd=$(( $count * 73 / $total ))
runtime=$(( $cur-$start ))
estremain=$(( ($runtime * $total / $count)-$runtime ))
printf "\r%d.%d%% complete ($count of $total) - est %d:%0.2d remaining\e[K" $(( $count*100/$total )) $(( ($count*1000/$total)%10)) $(( $estremain/60 )) $(( $estremain%60 ))
done
printf "\ndone\n"
Ссылка на здесь - хорошая функция spinner (с небольшой модификацией), поможет вашему курсору оставаться в исходном положении.
spinner()
{
local pid=$!
local delay=0.75
local spinstr='|/-\'
while [ "$(ps a | awk '{print $1}' | grep $pid)" ]; do
local temp=${spinstr#?}
printf " [%c] " "$spinstr"
local spinstr=$temp${spinstr%"$temp"}
sleep $delay
printf "\b\b\b\b\b\b"
done
printf " \b\b\b\b"
}
с использованием:
(a_long_running_task) &
spinner
Это довольно простой способ:
(просто замените sleep 20
на любую команду, которую вы хотите указать)
#!/bin/bash
sleep 20 & PID=$! #simulate a long process
echo "THIS MAY TAKE A WHILE, PLEASE BE PATIENT WHILE ______ IS RUNNING..."
printf "["
# While process is running...
while kill -0 $PID 2> /dev/null; do
printf "▓"
sleep 1
done
printf "] done!"
Результат выглядит следующим образом:
> THIS MAY TAKE A WHILE, PLEASE BE PATIENT WHILE ______ IS RUNNING...
> [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] done!
Он добавляет ▓
(точка с высокой плотностью) каждую секунду, пока процесс не будет завершен.
Вот простой onliner, который я использую:
while true; do for X in '-' '/' '|' '\'; do echo -en "\b$X"; sleep 0.1; done; done
Помимо классического счетчика, вы можете использовать этот индикатор выполнения
Он достигает точности субхарактера, используя символы половинного блока
Код включен в ссылку.
Здесь моя попытка. Я новичок в скриптах bash, поэтому некоторые из этого кода могут быть ужасными:)
Результат:
Код:
progressBarWidth=20
# Function to draw progress bar
progressBar () {
# Calculate number of fill/empty slots in the bar
progress=$(echo "$progressBarWidth/$taskCount*$tasksDone" | bc -l)
fill=$(printf "%.0f\n" $progress)
if [ $fill -gt $progressBarWidth ]; then
fill=$progressBarWidth
fi
empty=$(($fill-$progressBarWidth))
# Percentage Calculation
percent=$(echo "100/$taskCount*$tasksDone" | bc -l)
percent=$(printf "%0.2f\n" $percent)
if [ $(echo "$percent>100" | bc) -gt 0 ]; then
percent="100.00"
fi
# Output to screen
printf "\r["
printf "%${fill}s" '' | tr ' ' ▉
printf "%${empty}s" '' | tr ' ' ░
printf "] $percent%% - $text "
}
## Collect task count
taskCount=33
tasksDone=0
while [ $tasksDone -le $taskCount ]; do
# Do your task
(( tasksDone += 1 ))
# Add some friendly output
text=$(echo "somefile-$tasksDone.dat")
# Draw the progress bar
progressBar $taskCount $taskDone $text
sleep 0.01
done
echo
Здесь вы можете увидеть источник: https://gist.github.com/F1LT3R/fa7f102b08a514f2c535
Вот пример "индикатора активности" для проверки скорости интернет-соединения с помощью команды linux "speedtest-cli":
printf '\n\tInternet speed test: '
# http://stackoverflow.com/questions/12498304/using-bash-to-display-a-progress-working-indicator
spin[0]="-"
spin[1]="\\"
spin[2]="|"
spin[3]="/"
# http://stackoverflow.com/questions/20165057/executing-bash-loop-while-command-is-running
speedtest > .st.txt & ## & : continue running script
pid=$! ## PID of last command
# If this script is killed, kill 'speedtest':
trap "kill $pid 2> /dev/null" EXIT
# While 'speedtest' is running:
while kill -0 $pid 2> /dev/null; do
for i in "${spin[@]}"
do
echo -ne "\b$i"
sleep 0.1
done
done
# Disable the trap on a normal exit:
trap - EXIT
printf "\n\t "
grep Download: .st.txt
printf "\t "
grep Upload: .st.txt
echo ''
rm -f st.txt
Обновление - пример:
Я расширил ответ контрольной суммы в его ответе, отобразив сообщение с переменной информацией после счетчика:
#!/usr/bin/env bash
function spinner() {
local info="$1"
local pid=$!
local delay=0.75
local spinstr='|/-\'
while kill -0 $pid 2> /dev/null; do
local temp=${spinstr#?}
printf " [%c] $info" "$spinstr"
local spinstr=$temp${spinstr%"$temp"}
sleep $delay
local reset="\b\b\b\b\b\b"
for ((i=1; i<=$(echo $info | wc -c); i++)); do
reset+="\b"
done
printf $reset
done
printf " \b\b\b\b"
}
# usage:
(a_long_running_task) &
spinner "performing long running task..."
Мне не нравится, если вывод stdout со спиннером перенаправляется в файл, less
показывает ^H
для каждого возврата, вместо того, чтобы вообще избегать их в выводе файла. Возможно ли это с помощью простого прядильщика, подобного этому?
https://github.com/extensionsapp/progre.sh
Создайте 82-процентный прогресс: progreSh 82
@DavidD комментирует ответ Pez Cuckows, это пример того, как вы можете захватить вывод индикатора выполнения в script и по-прежнему смотреть на счетчик на экране:
#!/usr/bin/env bash
#############################################################################
###########################################################################
###
### Modified/Rewritten by A.M.Danischewski (c) 2015 v1.1
### Issues: If you find any issues emai1 me at my <first name> dot
### <my last name> at gmail dot com.
###
### Based on scripts posted by Pez Cuckow, William Pursell at:
### http://stackoverflow.com/questions/12498304/using-bash-to-display-\
### a-progress-working-indicator
###
### This program runs a program passed in and outputs a timing of the
### command and it exec a new fd for stdout so you can assign a
### variable the output of what was being run.
###
### This is a very new rough draft but could be expanded.
###
### This program is free software: you can redistribute it and/or modify
### it under the terms of the GNU General Public License as published by
### the Free Software Foundation, either version 3 of the License, or
### (at your option) any later version.
###
### This program is distributed in the hope that it will be useful,
### but WITHOUT ANY WARRANTY; without even the implied warranty of
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
### GNU General Public License for more details.
###
### You should have received a copy of the GNU General Public License
### along with this program. If not, see <http://www.gnu.org/licenses/>.
###########################################################################
#############################################################################
declare CMD="${1}"
shift ## Clip the first value of the [email protected], the rest are the options.
declare CMD_OPTIONS="[email protected]"
declare CMD_OUTPUT=""
declare TMP_OUTPUT="/tmp/_${0##*/}_$$_$(date +%Y%m%d%H%M%S%N)"
declare -r SPIN_DELAY="0.1"
declare -i PID=
function usage() {
cat <<EOF
Description: ${0##*/}
This program runs a program passed in and outputs a timing of the
command and it exec a new fd for stdout so you can assign a variable
the output of what was being run.
Usage: ${0##*/} <command> [command options]
E.g.
>$ ${0##*/} sleep 5 \&\& echo "hello" \| figlet
Running: sleep 5 && echo hello | figlet, PID 2587:/
real 0m5.003s
user 0m0.000s
sys 0m0.002s
_ _ _
| |__ ___| | | ___
| '_ \ / _ \ | |/ _ \
| | | | __/ | | (_) |
|_| |_|\___|_|_|\___/
Done..
>$ var=\$(${0##*/} sleep 5 \&\& echo hi)
Running: sleep 5 && echo hi, PID 32229:-
real 0m5.003s
user 0m0.000s
sys 0m0.001s
Done..
>$ echo \$var
hi
EOF
}
function spin_wait() {
local -a spin
spin[0]="-"
spin[1]="\\"
spin[2]="|"
spin[3]="/"
echo -en "Running: ${CMD} ${CMD_OPTIONS}, PID ${PID}: " >&3
while kill -0 ${PID} 2>/dev/random; do
for i in "${spin[@]}"; do
echo -ne "\b$i" >&3
sleep ${SPIN_DELAY}
done
done
}
function run_cmd() {
exec 3>$(tty)
eval "time ${CMD} ${CMD_OPTIONS}" 2>>"${TMP_OUTPUT}" | tee "${TMP_OUTPUT}" &
PID=$! # Set global PID to process id of the command we just ran.
spin_wait
echo -en "\n$(< "${TMP_OUTPUT}")\n" >&3
echo -en "Done..\n" >&3
rm "${TMP_OUTPUT}"
exec 3>&-
}
if [[ -z "${CMD}" || "${CMD}" =~ ^-. ]]; then
usage | more && exit 0
else
run_cmd
fi
exit 0
Психоделический индикатор выполнения для bash сценариев. Вызовите по командной строке как. /progressbar x y, где "x" - это время в секундах, а "y" - это сообщение для отображения. Внутренняя функция progressbar() работает автономно, а также принимает "x" в процентах и "y" в качестве сообщения.
#!/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
echo -e "\n"
};
timeprogress "$1" "$2"