当在bash或*NIX中的任何其他shell中编写脚本时,在运行需要超过几秒钟时间的命令时,需要一个进度条。
例如,复制一个大文件,打开一个大tar文件。
你建议用什么方法向shell脚本添加进度条?
当在bash或*NIX中的任何其他shell中编写脚本时,在运行需要超过几秒钟时间的命令时,需要一个进度条。
例如,复制一个大文件,打开一个大tar文件。
你建议用什么方法向shell脚本添加进度条?
当前回答
我想根据命令输出的行数和之前运行的目标行数来跟踪进度:
#!/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
它输出一个进度条,看起来像这样:
[===============================================> ]
条形图随着输出行数达到目标而增长。如果行数超过了目标,条就重新开始(希望目标是好的)。
BTW:我在Mac OSX上使用bash。我基于这个代码从mariascio旋转。
其他回答
根据上面列出的建议,我决定实现自己的进度条。
#!/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 "$@"
前几天我写了一个简单的进度条函数:
#!/bin/bash
# 1. Create ProgressBar function
# 1.1 Input is currentState($1) and totalState($2)
function ProgressBar {
# Process data
let _progress=(${1}*100/${2}*100)/100
let _done=(${_progress}*4)/10
let _left=40-$_done
# Build progressbar string lengths
_fill=$(printf "%${_done}s")
_empty=$(printf "%${_left}s")
# 1.2 Build progressbar strings and print the ProgressBar line
# 1.2.1 Output example:
# 1.2.1.1 Progress : [########################################] 100%
printf "\rProgress : [${_fill// /#}${_empty// /-}] ${_progress}%%"
}
# Variables
_start=1
# This accounts as the "totalState" variable for the ProgressBar function
_end=100
# Proof of concept
for number in $(seq ${_start} ${_end})
do
sleep 0.1
ProgressBar ${number} ${_end}
done
printf '\nFinished!\n'
或者从, https://github.com/fearside/ProgressBar/
我在寻找比选定的答案更性感的东西,我自己的剧本也是如此。
预览
源
我把它放在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
我需要一个进度条来迭代csv文件中的行。能够将cprn的代码改编成对我有用的东西:
BAR='##############################'
FILL='------------------------------'
totalLines=$(wc -l $file | awk '{print $1}') # num. lines in file
barLen=30
# --- iterate over lines in csv file ---
count=0
while IFS=, read -r _ col1 col2 col3; do
# update progress bar
count=$(($count + 1))
percent=$((($count * 100 / $totalLines * 100) / 100))
i=$(($percent * $barLen / 100))
echo -ne "\r[${BAR:0:$i}${FILL:$i:barLen}] $count/$totalLines ($percent%)"
# other stuff
(...)
done <$file
看起来是这样的:
[##----------------------------] 17128/218210 (7%)