在bash或其他* NIX中运行脚本时,如果要运行的命令需要花费几秒钟以上的时间,则需要使用进度条。
例如,拷贝大文件,打开大的tar文件等。
您推荐使用哪些方法来为shell脚本添加进度条?
在bash或其他* NIX中运行脚本时,如果要运行的命令需要花费几秒钟以上的时间,则需要使用进度条。
例如,拷贝大文件,打开大的tar文件等。
您推荐使用哪些方法来为shell脚本添加进度条?
你可以通过覆盖一行来实现这一点。使用\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 在下面的评论中提到,如果您从一行长文开始,然后想写一行短文,则会 "失败":在这种情况下,您需要覆盖长文的长度(例如,使用空格)。
printf
而不是 echo
。 - Jensprintf "#### (50%%)\r"
,不能使用单引号,并且百分号需要转义。 - nurettin您可能对如何在Bash中制作旋转器也感兴趣:链接
当然可以!
每次循环迭代时,它会显示sp字符串中的下一个字符,并在到达末尾时进行换行 (i是要显示的当前字符的位置,${#sp}是sp字符串的长度)。
i=1 sp="/-\|" echo -n ' ' while true do printf "\b${sp:i++%${#sp}:1}" done
\b字符串将被替换为 'backspace' 字符。或者,你可以使用\r回到行的开头。
如果您想让它减慢速度,请在循环内部(printf之后)放置一个sleep命令。
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
while :;do for s in / - \\ \|; do printf "\r$s";sleep 1;done;done
(*注意:sleep
函数可能需要整数而不是小数作为参数)。 - Adam Katzjob=$!
),然后运行 while kill -0 $job 2>/dev/null;do …
,例如:sleep 15 & job=$!; while kill -0 $job 2>/dev/null; do for s in / - \\ \|; do printf "\r$s"; sleep .1; done; done
。 - Adam Katz我前几天写了一个简单的进度条函数:
#!/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/
printf "\r进度:[${_fill// /▇}${_empty// / }] ${_progress}%%"
- Mehdi LAMRANIprintf -v _fill“#。0s”$(seq 1 $ done)
。 - Jason Kohles我想找一个比选定答案更性感的东西,所以写了自己的脚本。
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
progress-bar 100
。 - jirarium$ wc -l blob &
[1] 3405769
$ lsof -w -o0 -o -c wc
COMMAND PID USER FD TYPE DEVICE OFFSET NODE NAME
[...]
wc 3405769 dds 3r REG 254,7 0t2656059392 7733716 blob
$ pmonitor -c gzip
/home/dds/data/mysql-2015-04-01.sql.gz 58.06%
lsof -w -o0 -o -c command
命令行以及可能对其功能或如何阅读输出进行简要解释。 - cprn我没有看到类似的东西,这里的所有自定义函数似乎都只关注渲染,因此......以下是我非常简单、符合 POSIX 标准的解决方案,包含逐步说明,因为这个问题并不简单。
渲染进度条非常容易,但确定应该渲染多少则不同。以下是如何渲染(动画)进度条的方法 - 您可以将此示例复制并粘贴到文件中运行:
#!/bin/sh
BAR='####################' # this is full bar, e.g. 20 chars
for i in {1..20}; do
echo -ne "\r${BAR:0:$i}" # print $i chars of $BAR from 0 position
sleep .1 # wait 100ms between "frames"
done
{1..20}
- 从1到20的值echo
- 输出到终端(即stdout
)echo -n
- 输出时不换行echo -e
- 在输出时解释特殊字符"\r"
- 回车符,用于回到行首你可以以任何速度渲染任何内容,因此这种方法非常通用,在愚蠢的电影中常用于“黑客”可视化,不开玩笑。
问题的核心在于如何确定$i
的值,即进度条要显示多少。在上面的示例中,我只是让它在for
循环中递增,以说明原则,但实际应用程序将使用无限循环并在每次迭代中计算$i
变量。为了进行该计算,需要以下要素:
对于cp
,需要源文件和目标文件的大小:
#!/bin/sh
src="/path/to/source/file"
tgt="/path/to/target/file"
cp "$src" "$tgt" & # the & forks the `cp` process so the rest
# of the code runs without waiting (async)
BAR='####################'
src_size=$(stat -c%s "$src") # how much there is to do
while true; do
tgt_size=$(stat -c%s "$tgt") # how much has been done so far
i=$(( $tgt_size * 20 / $src_size ))
echo -ne "\r${BAR:0:$i}"
if [ $tgt_size == $src_size ]; then
echo "" # add a new line at the end
break; # break the loop
fi
sleep .1
done
foo=$(bar)
- 运行bar
子进程并将其stdout
保存到$foo
stat
- 将文件统计信息打印到stdout
stat -c
- 打印格式化的值%s
- 总大小的格式化方式对于像文件解压缩等操作,计算源大小略微困难,但仍然与获取未压缩文件的大小一样容易:
#!/bin/sh
src_size=$(gzip -l "$src" | tail -n1 | tr -s ' ' | cut -d' ' -f3)
gzip -l
- 打印有关zip存档的信息tail -n1
- 从底部处理1行tr -s ' '
- 将多个空格转换为一个(“挤压”它们)cut -d' ' -f3
- 剪切第3个以空格分隔的字段(列)这是我之前提到的问题的核心。该解决方案越来越不通用。所有有关实际进度的计算都与您试图可视化的域紧密绑定,是单个文件操作、计时器倒计时、目录中文件数量逐渐增加、对多个文件的操作等,因此,它不能被重复使用。唯一可重复使用的部分是进度条呈现。要重用它,您需要将其抽象化并保存在文件中(例如/ usr / lib / progress_bar.sh
),然后定义计算特定于您领域的输入值的函数。这是通用代码的样子(我还使$BAR
动态,因为人们正在询问它,其余部分现在应该很清楚):
#!/bin/bash
BAR_length=50
BAR_character='#'
BAR=$(printf %${BAR_length}s | tr ' ' $BAR_character)
work_todo=$(get_work_todo) # how much there is to do
while true; do
work_done=$(get_work_done) # how much has been done so far
i=$(( $work_done * $BAR_length / $work_todo ))
echo -ne "\r${BAR:0:$i}"
if [ $work_done == $work_todo ]; then
echo ""
break;
fi
sleep .1
done
printf
- 以给定的格式打印输出内容的内置命令。printf %50s
- 打印空字符串,但在前面填充50个空格。tr ' ' '#'
- 将每个空格字符转换为井号。以下是使用方法示例:
#!/bin/bash
src="/path/to/source/file"
tgt="/path/to/target/file"
function get_work_todo() {
echo $(stat -c%s "$src")
}
function get_work_done() {
[ -e "$tgt" ] && # if target file exists
echo $(stat -c%s "$tgt") || # echo its size, else
echo 0 # echo zero
}
cp "$src" "$tgt" & # copy in the background
source /usr/lib/progress_bar.sh # execute the progress bar
显然,你可以将其封装在一个函数中,重写以使用管道流工作,使用 $!
获取分叉的进程 ID,并将其传递给 progress_bar.sh
,以便它可以“猜测”如何计算要做的工作和已完成的工作,任何你想要的方式都可以。
我最常被问到的两件事:
${}
:在上面的示例中,我使用了 ${foo:A:B}
。这种语法的技术术语是“参数扩展”,它是内置的 shell 功能,允许操作变量(参数),例如使用 :
去掉字符串的空格,但也可以做其他事情 - 它不会生成子 Shell。我能想到的最著名的参数扩展描述(并非完全符合 POSIX 标准,但有助于读者理解概念)在 man bash
页面中。$()
:在上面的示例中,我使用了 foo=$(bar)
。它会在子进程(即子外壳)中生成一个单独的 Shell,运行其中的 bar
命令,并将其标准输出分配给 $foo
变量。它与 Process Substitution 不同,也与 pipe (|
) 完全不同。最重要的是,它可行。有些人认为应该避免使用它,因为它很慢。我认为这在这里是“可以的”,因为无论这段代码试图可视化什么都需要花费足够长的时间才需要一个进度条。换句话说,子 Shell 并不是瓶颈。调用子 Shell 还省去了我解释为什么 return
不是大多数人想象中那样,什么是 Exit Status,以及为什么总体而言从 shell 函数传递值不是 shell 函数擅长的事情。要了解更多信息,我再次强烈推荐阅读 man bash
页面。如果你的 shell 实际上运行的是 sh 而不是 bash,或者非常旧的 bash,例如默认的 osx,则可能会出现 echo -ne "\r${BAR:0:$i}"
的问题。确切的错误是“Bad substitution”。如果发生这种情况,根据评论部分,您可以改用 echo -ne "\r$(expr "x$name" : "x.\{0,$num_skip\}\(.\{0,$num_keep\}\)")"
来执行更多可移植的 POSIX 兼容 / 可读性较差的子字符串匹配。
一个完整的、可用的 /bin/sh 示例:
#!/bin/sh
src=100
tgt=0
get_work_todo() {
echo $src
}
do_work() {
echo "$(( $1 + 1 ))"
}
BAR_length=50
BAR_character='#'
BAR=$(printf %${BAR_length}s | tr ' ' $BAR_character)
work_todo=$(get_work_todo) # how much there is to do
work_done=0
while true; do
work_done="$(do_work $work_done)"
i=$(( $work_done * $BAR_length / $work_todo ))
n=$(( $BAR_length - $i ))
printf "\r$(expr "x$BAR" : "x.\{0,$n\}\(.\{0,$i\}\)")"
if [ $work_done = $work_todo ]; then
echo "\n"
break;
fi
sleep .1
done
${BAR:0:$i}
可能会导致一些人出现“Bad substitution”的错误。 - NoxFlysh
链接到 bash
或运行 bash --posix
兼容模式的脚本,我怀疑在我编写和测试这个答案的2016年,我的系统也是如此。如果它对你不起作用,你可以将 ${name:n:l}
替换为 $(expr "x$name" : "x.\{0,$n\}\(.\{0,$l\}\)")
,这已经被证明在任何 POSIX shell 中都可以工作(源自 ksh93
,也存在于 zsh
、mksh
和 busyboxsh
中)。尽管如此,我仍然保留原始答案,因为它应该在绝大多数情况下都能正常工作,并且易于阅读。 - cprn对于这个不太短的答案,我将使用整数
来呈现浮点数,UTF-8
字体以更精细地呈现进度条,并并行化
另一个任务(sha1sum
)以跟踪其进展,所有这些都使用纯bash和无forks的最小资源占用。
对于快速鸢尾属植物:请在中间的现在就来!处测试代码(复制/粘贴到新的终端窗口),使用以下任一选项:
- 要么:最后一个动画演示(接近结尾),
- 要么:实用样例(在结尾处)。
所有演示都使用read -t <float seconds> && break
而不是sleep
。因此,通过按下回车键可以很好地停止所有循环。
又一个Bash进度条...
由于这里已经有了很多答案,我想添加一些关于性能和精度的提示。
因为进度条旨在在其他进程正在工作时运行,所以这必须是一个良好的过程...
所以在不必要的情况下避免使用forks。例如:可以使用...mysmiley=$(printf '%b' \\U1F60E)
使用
printf -v mysmiley '%b' \\U1F60E
说明:当你运行var=$(command)
时,你启动了一个新的进程来执行command
并将其输出发送到变量$var
一旦终止。这是非常消耗资源的。请比较:TIMEFORMAT="%R"
time for ((i=2500;i--;)){ mysmiley=$(printf '%b' \\U1F60E);}
2.292
time for ((i=2500;i--;)){ printf -v mysmiley '%b' \\U1F60E;}
0.017
bc -l <<<'2.292/.017'
134.82352941176470588235
$mysmiley
的工作(只有2500次),使用fork比使用内置的printf -v
要慢约135倍/更昂贵。echo $mysmiley
因此,您的函数
不得打印(或输出)任何内容。您的函数必须将其答案归因于一个变量。
这是一个非常小而快速的函数,用于从整数计算百分比,并使用整数并返回一个伪浮点数:
percent(){
local p=00$(($1*100000/$2))
printf -v "$3" %.2f ${p::-3}.${p: -3}
}
使用方法:
# percent <integer to compare> <reference integer> <variable name>
percent 33333 50000 testvar
printf '%8s%%\n' "$testvar"
66.67%
▏ ▎ ▍ ▌ ▋ ▊ ▉ █
要在 bash 中渲染这些字符,您可以:
printf -v chars '\\U258%X ' {15..8}
printf '%b\n' "$chars"
▏ ▎ ▍ ▌ ▋ ▊ ▉ █
或者
printf %b\ \\U258{{f..a},9,8}
▏ ▎ ▍ ▌ ▋ ▊ ▉ █
那么我们必须将字符串宽度
的8倍用作图形宽度
。
这个函数被命名为percentBar
,因为它可以根据以百分比(浮点数)提交的参数呈现一个条形图:
percentBar () {
local prct totlen=$((8*$2)) lastchar barstring blankstring;
printf -v prct %.2f "$1"
((prct=10#${prct/.}*totlen/10000, prct%8)) &&
printf -v lastchar '\\U258%X' $(( 16 - prct%8 )) ||
lastchar=''
printf -v barstring '%*s' $((prct/8)) ''
printf -v barstring '%b' "${barstring// /\\U2588}$lastchar"
printf -v blankstring '%*s' $(((totlen-prct)/8)) ''
printf -v "$3" '%s%s' "$barstring" "$blankstring"
}
使用方法:
# percentBar <float percent> <int string width> <variable name>
percentBar 42.42 $COLUMNS bar1
echo "$bar1"
█████████████████████████████████▉
percentBar 42.24 $COLUMNS bar2
printf "%s\n" "$bar1" "$bar2"
█████████████████████████████████▉
█████████████████████████████████▊
由于渲染的变量是固定宽度的字符串,使用颜色很容易:
percentBar 72.1 24 bar
printf 'Show this: \e[44;33;1m%s\e[0m at %s%%\n' "$bar" 72.1
for i in {0..10000..33} 10000;do i=0$i
printf -v p %0.2f ${i::-2}.${i: -2}
percentBar $p $((COLUMNS-9)) bar
printf '\r|%s|%6.2f%%' "$bar" $p
read -srt .002 _ && break # console sleep avoiding fork
done
|███████████████████████████████████████████████████████████████████████|100.00%
clear; for i in {0..10000..33} 10000;do i=0$i
printf -v p %0.2f ${i::-2}.${i: -2}
percentBar $p $((COLUMNS-7)) bar
printf '\r\e[47;30m%s\e[0m%6.2f%%' "$bar" $p
read -srt .002 _ && break
done
另一个演示展示不同尺寸和颜色输出:
printf '\n\n\n\n\n\n\n\n\e[8A\e7'&&for i in {0..9999..99} 10000;do
o=1 i=0$i;printf -v p %0.2f ${i::-2}.${i: -2}
for l in 1 2 3 5 8 13 20 40 $((COLUMNS-7));do
percentBar $p $l bar$((o++));done
[ "$p" = "100.00" ] && read -rst .8 _;printf \\e8
printf '%s\e[48;5;23;38;5;41m%s\e[0m%6.2f%%%b' 'In 1 char width: ' \
"$bar1" $p ,\\n 'with 2 chars: ' "$bar2" $p ,\\n 'or 3 chars: ' \
"$bar3" $p ,\\n 'in 5 characters: ' "$bar4" $p ,\\n 'in 8 chars: ' \
"$bar5" $p .\\n 'There are 13 chars: ' "$bar6" $p ,\\n '20 chars: '\
"$bar7" $p ,\\n 'then 40 chars' "$bar8" $p \
', or full width:\n' '' "$bar9" $p ''
((10#$i)) || read -st .5 _; read -st .1 _ && break
done
可以生成类似以下内容:
sleep
2023年2月重写:转化为更有用的displaySleep
函数,适用于作为显示的超时读取:
这个sleep会显示一个带有50秒刷新的进度条(可调节)。
percent(){ local p=00$(($1*100000/$2));printf -v "$3" %.2f ${p::-3}.${p: -3};}
displaySleep() {
local -i refrBySeconds=50
local -i _start=${EPOCHREALTIME/.} reqslp target crtslp crtp cols cpos dlen
local strng percent prctbar tleft
[[ $COLUMNS ]] && cols=${COLUMNS} || read -r cols < <(tput cols)
refrBySeconds=' 1000000 / refrBySeconds '
printf -v strng %.6f $1
printf '\E[6n' && IFS=\; read -sdR _ cpos
dlen=${#strng}-1 cols=' cols - dlen - cpos -1 '
printf \\e7
reqslp=10#${strng/.} target=reqslp+_start
for ((;${EPOCHREALTIME/.}<target;)){
crtp=${EPOCHREALTIME/.}
crtslp='( target - crtp ) > refrBySeconds? refrBySeconds: target - crtp'
strng=00000$crtslp crtp+=-_start
printf -v strng %.6f ${strng::-6}.${strng: -6}
percent $crtp $reqslp percent
percentBar $percent $cols prctbar
tleft=00000$((reqslp-crtp))
printf '\e8\e[36;48;5;23m%s\e[0m%*.4fs' \
"$prctbar" "$dlen" ${tleft::-6}.${tleft: -6}
IFS= read -rsn1 -t $strng ${2:-_} && { echo; return;}
}
percentBar 100 $cols prctbar
printf '\e8\e[36;48;5;30m%s\e[0m%*.4fs\n' "$prctbar" "$dlen" 0
false
}
sha1sum
在Linux下,您可以在/proc
伪文件系统下找到许多有用的信息,因此使用先前定义的函数percentBar
和percent
,这里是sha1progress
:
percent(){ local p=00$(($1*100000/$2));printf -v "$3" %.2f ${p::-3}.${p: -3};}
sha1Progress() {
local -i totsize crtpos cols=$(tput cols) sha1in sha1pid
local sha1res percent prctbar
exec {sha1in}< <(exec sha1sum -b - <"$1")
sha1pid=$!
read -r totsize < <(stat -Lc %s "$1")
while ! read -ru $sha1in -t .025 sha1res _; do
read -r _ crtpos < /proc/$sha1pid/fdinfo/0
percent $crtpos $totsize percent
percentBar $percent $((cols-8)) prctbar
printf '\r\e[44;38;5;25m%s\e[0m%6.2f%%' "$prctbar" $percent;
done
printf "\r%s %s\e[K\n" $sha1res "$1"
}
25毫秒
的超时意味着大约每秒刷新40次。这看起来可能过度了一些,但它在我的主机上运行良好,而且无论如何,这可以进行调整。
解释:
exec {sha1in}<
为输出创建一个新的文件描述符<( ... )
后台运行分叉的任务sha1sum -b - <"$1"
确保输入来自STDIN (fd/0
)while ! read -ru $sha1in -t .025 sha1res _
当子任务没有读取到输入时,在25毫秒
内执行.../proc/$sha1pid/fdinfo/0
内核变量,显示任务$sha1pid
的文件描述符0 (STDIN)的信息\r
会导致光标重置,因此该条重新绘制自己,但在第二个动画演示中,您是如何实现这一点的? - DavidEsc[8A
将光标返回8行。接着使用 Esc7
保存光标位置... 之后使用 Esc8
恢复光标位置。 - F. Hauri - Give Up GitHub编辑:查看更新版本请访问我的github页面
我对这个问题的回答并不满意。我想要的是一个像APT一样花哨的进度条。
我查看了APT的C源代码,并决定为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}"
}
var=$(printf...)
,而是写printf -v var ...
,也不要写var=$(echo -n ...;printf)
,而是写printf -v var ...; var=...${var}...
。 - F. Hauri - Give Up GitHubGNU tar具有一个实用的选项,可以提供简单进度条的功能。
(...) 另一个可用的检查点操作是“点”(或“.”)。它指示tar在标准列表流上打印一个点,例如:
$ tar -c --checkpoint=1000 --checkpoint-action=dot /var
...
通过以下方式也可以达到相同的效果:
$ tar -c --checkpoint=.1000 /var
--checkpoint=.10
。当使用 tar -xz
进行提取时,它也非常有效。最简单的方法加一! - Noam Manos
pv
。例如:ssh remote "cd /home/user/ && tar czf - accounts" | pv -s 23091k | tar xz
。 - bitsoflogic