如何向shell脚本添加进度条?

Tom*_*ner 390 bash shell zsh

在bash或*NIX中的任何其他shell中编写脚本时,在运行将需要几秒钟的命令时,需要一个进度条.

例如,复制一个大文件,打开一个大的tar文件.

您建议以哪些方式向shell脚本添加进度条?

Mit*_*ile 665

您可以通过覆盖一行来实现此目的.用于\r返回到行的开头而不写入\n终端.

\n当你完成前进就行了.

使用echo -ne于:

  1. 不打印\n
  2. 识别转义序列\r.

这是一个演示:

echo -ne '#####                     (33%)\r'
sleep 1
echo -ne '#############             (66%)\r'
sleep 1
echo -ne '#######################   (100%)\r'
echo -ne '\n'
Run Code Online (Sandbox Code Playgroud)

在下面的评论中,如果你从一个长行开始然后想写一个短行,puk提到这个"失败":在这种情况下,你需要覆盖长行的长度(例如,用空格).

  • 输出它的便携方式是使用`printf`而不是`echo`. (49认同)
  • 根据**echo**手册页(至少在MacOS X上)sh/bash使用自己内置的**echo**命令,不接受"-n"...所以为了完成同样的事情你需要把**\r\c**放在字符串的末尾,而不仅仅是**\r** (21认同)
  • 问题是"我如何进行进度条"以复制文件为例.我专注于"图形"问题,而不是计算文件复制操作的距离. (16认同)
  • 对于printf,我们必须使用这种格式:`printf"####(50 %%)\ r"`,它不适用于单引号,百分号需要转义. (9认同)
  • 我没有得到这个 - 被接受和大量的赞成"我猜这个操作将在未知的硬件上花多长时间"黑客?[pv](http://stackoverflow.com/a/6863190/37193)是正确答案IMO(但[bar](/sf/answers/299338581/)也会这样做) (4认同)
  • `echo -n $'#####(33%)\ r'`适用于MacOS X(注意美元符号). (2认同)

Dae*_*yth 67

您可能还对如何进行微调器感兴趣:

我可以用Bash做一个微调器吗?

当然!

i=1
sp="/-\|"
echo -n ' '
while true
do
    printf "\b${sp:i++%${#sp}:1}"
done
Run Code Online (Sandbox Code Playgroud)

每次循环迭代时,它都会显示sp字符串中的下一个字符,并在到达结尾时回绕.(i是要显示的当前字符的位置,$ {#sp}是sp字符串的长度).

\ b字符串由'backspace'字符替换.或者,您可以使用\ r来回到行的开头.

如果你想让它变慢,可以在循环中放入一个sleep命令(在printf之后).

POSIX等价物将是:

sp='/-\|'
printf ' '
while true; do
    printf '\b%.1s' "$sp"
    sp=${sp#?}${sp%???}
done
Run Code Online (Sandbox Code Playgroud)

如果您已经有一个执行大量工作的循环,则可以在每次迭代开始时调用以下函数来更新微调器:

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
Run Code Online (Sandbox Code Playgroud)

  • 更短的版本,完全可移植*:`while :; do for s in/ - \\\|; do printf"\ r $ s"; sleep .1; done; done`(*:`sleep`可能需要整数而不是小数) (15认同)

Dio*_*lis 48

一些帖子展示了如何显示命令的进度.为了计算它,你需要看看你进步了多少.在BSD系统上,某些命令(例如dd(1))接受SIGINFO信号,并将报告其进度.在Linux系统上,某些命令的响应类似于SIGUSR1.如果此工具可用,您可以通过管道输入dd来监视已处理的字节数.

或者,您可以使用lsof获取文件读取指针的偏移量,从而计算进度.我编写了一个名为pmonitor的命令,它显示处理指定进程或文件的进度.有了它,你可以做一些事情,如下所示.

$ pmonitor -c gzip
/home/dds/data/mysql-2015-04-01.sql.gz 58.06%
Run Code Online (Sandbox Code Playgroud)

早期版本的Linux和FreeBSD shell脚本出现在我的博客上.


小智 40

使用linux命令pv:

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

如果它在流的中间,它不知道大小,但是它给出了一个速度和总和,从那里你可以弄清楚应该花多长时间并获得反馈,这样你就知道它没有挂起.


小智 39

我前几天写了一个简单的进度条功能:

#!/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'
Run Code Online (Sandbox Code Playgroud)

或者从中获取,
https://github.com/fearside/ProgressBar/


F. *_*uri 31

雇用(浮点)进度条

\n

前言

\n

抱歉,这个答案不那么简短。在这个答案中,我将使用integer渲染浮点,UTF-8更精细地渲染进度条的字体,以及parallelise另一个任务(sha1sum)来跟踪他的进度,所有这些都使用没有 fork来最小化资源占用。

\n
\n

对于凤仙花:请测试代码(复制/粘贴到新的终端窗口中),现在就开始吧!(在中间),与

\n
    \n
  • 要么:最后一个动画演示(接近尾声。),
  • \n
  • 任一实用示例(最后)。
  • \n
\n
\n

这里的所有演示都使用read -t <float seconds> && break而不是sleep. 所以所有的循环都可以通过Return按键来很好地停止。

\n

介绍

\n

另一个 Bash 进度条...

\n

由于这里已经有很多答案,我想添加一些有关性能精度的提示。

\n

1.避免分叉!

\n

因为进度条旨在在其他进程运行时运行,所以这一定是一个很好的过程......

\n

因此,在不需要时避免使用叉子。示例:代替

\n
mysmiley=$(printf \'%b\' \\\\U1F60E)\n
Run Code Online (Sandbox Code Playgroud)\n

使用

\n
printf -v mysmiley \'%b\' \\\\U1F60E\n
Run Code Online (Sandbox Code Playgroud)\n

说明:当您运行 时var=$(command),您会启动一个新进程来执行command,并在终止后将其输出发送到变量$var。这是非常昂贵的资源。请比较:

\n
TIMEFORMAT="%R"\ntime for ((i=2500;i--;)){ mysmiley=$(printf \'%b\' \\\\U1F60E);}\n2.292\ntime for ((i=2500;i--;)){ printf -v mysmiley \'%b\' \\\\U1F60E;}\n0.017\nbc -l <<<\'2.292/.017\'\n134.82352941176470588235\n
Run Code Online (Sandbox Code Playgroud)\n

在我的主机上,使用fork进行相同的分配工作$mysmiley(只需 2500 次),似乎比使用内置.printf -v

\n

然后

\n
echo $mysmiley \n\n
Run Code Online (Sandbox Code Playgroud)\n

所以你function必须不打印(或输出)任何东西。你的函数必须将他的答案归因于一个变量

\n

2.使用整数作为伪浮点数

\n

这是一个非常小而快速的函数,用于计算整数的百分比,使用整数并回答伪浮点数:

\n
percent(){\n    local p=00$(($1*100000/$2))\n    printf -v "$3" %.2f ${p::-3}.${p: -3}\n}\n
Run Code Online (Sandbox Code Playgroud)\n

用法:

\n
# percent <integer to compare> <reference integer> <variable name>\npercent 33333 50000 testvar\nprintf \'%8s%%\\n\' "$testvar"\n   66.67%\n
Run Code Online (Sandbox Code Playgroud)\n

3. 使用 UTF-8 租用控制台图形:\xe2\x96\x8f \xe2\x96\x8e \xe2\x96\x8d \xe2\x96\x8c \xe2\x96\x8b \xe2\x96\x8a \xe2\x96\x89 \xe2\x96\x88

\n

要使用 bash 渲染这些字符,您可以:

\n
printf -v chars \'\\\\U258%X \' {15..8}\nprintf \'%b\\n\' "$chars"\n\xe2\x96\x8f \xe2\x96\x8e \xe2\x96\x8d \xe2\x96\x8c \xe2\x96\x8b \xe2\x96\x8a \xe2\x96\x89 \xe2\x96\x88 \n
Run Code Online (Sandbox Code Playgroud)\n

或者

\n
printf %b\\  \\\\U258{{f..a},9,8}\n\xe2\x96\x8f \xe2\x96\x8e \xe2\x96\x8d \xe2\x96\x8c \xe2\x96\x8b \xe2\x96\x8a \xe2\x96\x89 \xe2\x96\x88\n
Run Code Online (Sandbox Code Playgroud)\n

然后我们必须使用 8xstring width作为graphic width

\n

现在就做吧!

\n

此函数之所以如此命名,percentBar是因为它从以百分比形式提交的参数中呈现一个条形(浮动):

\n
percentBar ()  { \n    local prct totlen=$((8*$2)) lastchar barstring blankstring;\n    printf -v prct %.2f "$1"\n    ((prct=10#${prct/.}*totlen/10000, prct%8)) &&\n        printf -v lastchar \'\\\\U258%X\' $(( 16 - prct%8 )) ||\n            lastchar=\'\'\n    printf -v barstring \'%*s\' $((prct/8)) \'\'\n    printf -v barstring \'%b\' "${barstring// /\\\\U2588}$lastchar"\n    printf -v blankstring \'%*s\' $(((totlen-prct)/8)) \'\'\n    printf -v "$3" \'%s%s\' "$barstring" "$blankstring"\n}\n
Run Code Online (Sandbox Code Playgroud)\n

用法:

\n
# percentBar <float percent> <int string width> <variable name>\npercentBar 42.42 $COLUMNS bar1\necho "$bar1"\n\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x89                                              \n
Run Code Online (Sandbox Code Playgroud)\n

为了显示微小的差异:

\n
percentBar 42.24 $COLUMNS bar2\nprintf "%s\\n" "$bar1" "$bar2"\n\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x89                                              \n\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x8a                                              \n
Run Code Online (Sandbox Code Playgroud)\n

有颜色

\n

由于渲染变量是固定宽度的字符串,因此使用颜色很容易:

\n
percentBar 72.1 24 bar\nprintf \'Show this: \\e[44;33;1m%s\\e[0m at %s%%\\n\' "$bar" 72.1\n
Run Code Online (Sandbox Code Playgroud)\n

有颜色的酒吧

\n

小动画:

\n
# percentBar <float percent> <int string width> <variable name>\npercentBar 42.42 $COLUMNS bar1\necho "$bar1"\n\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x89                                              \n
Run Code Online (Sandbox Code Playgroud)\n
percentBar 42.24 $COLUMNS bar2\nprintf "%s\\n" "$bar1" "$bar2"\n\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x89                                              \n\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x8a                                              \n
Run Code Online (Sandbox Code Playgroud)\n

百分比条动画

\n

最后的动画演示

\n

另一个演示显示不同的尺寸和彩色输出:

\n
percentBar 72.1 24 bar\nprintf \'Show this: \\e[44;33;1m%s\\e[0m at %s%%\\n\' "$bar" 72.1\n
Run Code Online (Sandbox Code Playgroud)\n

可以产生这样的东西:

\n

最后一个动画%Bar动画

\n

实用GNU/Linuxsleep示例 1:带有进度条的类型

\n

重写 2023 年 2 月:变成更有用的displaySleep函数,适合用作显示的超时读取

\n

此睡眠显示进度条,每秒刷新 50 次(可调)

\n
for i in {0..10000..33} 10000;do i=0$i\n    printf -v p %0.2f ${i::-2}.${i: -2}\n    percentBar $p $((COLUMNS-9)) bar\n    printf \'\\r|%s|%6.2f%%\' "$bar" $p\n    read -srt .002 _ && break    # console sleep avoiding fork\ndone\n\n|\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88|100.00%\n
Run Code Online (Sandbox Code Playgroud)\n

这将保持 当前光标位置仅填充行的其余部分(如果当前光标位置为 1,则填充整行)。这对于显示某种提示可能很有用:

\n

在此输入图像描述

\n

实用GNU/Linux示例2:sha1sum带进度条

\n

在linux下,你可以在伪文件系统下找到很多有用的信息/proc,所以使用之前定义的函数percentBarpercent,这里是sha1progress

\n
clear; for i in {0..10000..33} 10000;do i=0$i\n     printf -v p %0.2f ${i::-2}.${i: -2}\n     percentBar $p $((COLUMNS-7)) bar\n     printf \'\\r\\e[47;30m%s\\e[0m%6.2f%%\' "$bar" $p\n     read -srt .002 _ && break\ndone\n
Run Code Online (Sandbox Code Playgroud)\n

当然,25 ms超时意味着每秒大约刷新 40 次。这可能看起来有些过分,但在我的主机上工作得很好,而且无论如何,这是可以调整的。

\n

sha1进度样本

\n

解释:

\n
    \n
  • exec {sha1in}<为输出创建一个新的文件描述符
  • \n
  • <( ... )分叉任务在后台运行
  • \n
  • sha1sum -b - <"$1"确保输入来自 STDIN ( fd/0)
  • \n
  • while ! read -ru $sha1in -t .025 sha1res _虽然没有从子任务读取输入,但25 ms......
  • \n
  • /proc/$sha1pid/fdinfo/0显示有关任务的文件描述符 0 (STDIN)的信息的内核变量$sha1pid
  • \n
\n


Édo*_*pez 27

我正在寻找比选定答案更性感的东西,所以我自己的剧本也是如此.

预习

progress-bar.sh在行动中

资源

我把它放在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
}
Run Code Online (Sandbox Code Playgroud)

用法

 progress-bar 100
Run Code Online (Sandbox Code Playgroud)

  • 我不明白如何将其集成到某些过程长度未知的处理中。如果我的进程提前完成,如何停止进度条,例如解压缩文件。 (4认同)
  • @RajeshHatwar 你不能没有杂技。它只是漂亮的计时器,而不是进度条。 (4认同)
  • @faceless,它不在您提供的时间和倒计时代码的范围内 (2认同)

小智 17

GNU tar有一个有用的选项,它提供了一个简单进度条的功能.

(...)另一个可用的检查点动作是'dot'(或'.').它指示tar在标准列表流上打印单个点,例如:

$ tar -c --checkpoint=1000 --checkpoint-action=dot /var
...
Run Code Online (Sandbox Code Playgroud)

通过以下方式可以获得相同的效果:

$ tar -c --checkpoint=.1000 /var
Run Code Online (Sandbox Code Playgroud)


小智 13

一种更简单的方法,可以使用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
Run Code Online (Sandbox Code Playgroud)


nac*_*ker 12

我还想贡献自己的进度条

它通过使用Half unicode块实现了子字符精度

在此输入图像描述

代码包括在内


cpr*_*prn 9

没有看到类似的东西......我非常简单的解决方案:

#!/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
Run Code Online (Sandbox Code Playgroud)
  • {1..20} - 最后没有新行打印
  • echo -n - 打印时解释特殊字符
  • echo -e - 回车,返回行首的特殊字符

我很久以前在一个简单的"黑客视频"中使用它来模拟打字代码.;)

  • 对于那些想要最简单的东西的人,我刚刚用 cprn 第一个答案做了我的。这是一个非常简单的函数中的进度条,使用一些愚蠢的比例规则来绘制进度条:https://pastebin.com/9imhRLYX (2认同)

小智 7

这使您可以看到命令仍在执行:

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
Run Code Online (Sandbox Code Playgroud)

这将创建一个无限循环,在后台执行并回显 "." 每一秒.这将显示.在shell中.运行tar命令或任何所需的命令.当该命令完成执行时,然后终止在后台运行的最后一个作业 - 这是无限循环.

  • 这是唯一正确的答案,其他人只是 Scripting 101 玩具进度条,这些进度条毫无意义,对真正的、一次性的、不可追踪的(几乎所有)程序没有用。谢谢你。 (2认同)

Vag*_*eev 6

这是它的外观

上载档案

[##################################################] 100% (137921 / 137921 bytes)
Run Code Online (Sandbox Code Playgroud)

等待工作完成

[#########################                         ] 50% (15 / 30 seconds)
Run Code Online (Sandbox Code Playgroud)

实现它的简单功能

您可以将其复制粘贴到脚本中。它不需要其他任何工作。

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 (( $__max < 1 )); then __max=1; fi  # anti zero division protection
  local __percentage=$(( 100 - ($__max*100 - $__value*100) / $__max ))

  # Rescale the bar according to the progress bar width
  local __num_bar=$(( $__percentage * $PROGRESS_BAR_WIDTH / 100 ))

  # Draw progress bar
  printf "["
  for b in $(seq 1 $__num_bar); do printf "#"; done
  for s in $(seq 1 $(( $PROGRESS_BAR_WIDTH - $__num_bar ))); do printf " "; done
  printf "] $__percentage%% ($__value / $__max $__unit)\r"
}
Run Code Online (Sandbox Code Playgroud)

使用范例

在这里,我们上传文件并在每次迭代时重绘进度条。只要可以得到两个值:最大值和当前值,实际上执行什么作业都没有关系。

在下面的示例中,最大值为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"
Run Code Online (Sandbox Code Playgroud)


Dus*_*els 6

我需要一个进度条来迭代 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
Run Code Online (Sandbox Code Playgroud)

看起来像这样:

[##----------------------------] 17128/218210 (7%)
Run Code Online (Sandbox Code Playgroud)


Con*_*lls 5

大多数 unix 命令不会为您提供可以执行此操作的那种直接反馈。有些会为您提供可以使用的 stdout 或 stderr 输出。

对于像 tar 这样的东西,您可以使用 -v 开关并将输出通过管道传输到一个程序,该程序为它读取的每一行更新一个小动画。当 tar 写出一个文件列表时,它被解开,程序可以更新动画。要完成百分比,您必须知道文件的数量并计算行数。

据我所知,cp 没有提供这种输出。要监视 cp 的进度,您必须监视源文件和目标文件并观察目标的大小。您可以使用stat (2)系统调用编写一个小型 c 程序来获取文件大小。这将读取源文件的大小,然后轮询目标文件并根据写入日期的文件大小更新完整百分比条。


Adr*_*fas 5

根据 Edouard Lopez 的工作,我创建了一个适合屏幕大小的进度条,无论屏幕大小如何。一探究竟。

\n\n

在此输入图像描述

\n\n

它还发布在Git Hub上。

\n\n
#!/bin/bash\n#\n# Progress bar by Adriano Pinaffo\n# Available at https://github.com/adriano-pinaffo/progressbar.sh\n# Inspired on work by Edouard Lopez (https://github.com/edouard-lopez/progress-bar.sh)\n# Version 1.0\n# Date April, 28th 2017\n\nfunction error {\n  echo "Usage: $0 [SECONDS]"\n  case $1 in\n    1) echo "Pass one argument only"\n    exit 1\n    ;;\n    2) echo "Parameter must be a number"\n    exit 2\n    ;;\n    *) echo "Unknown error"\n    exit 999\n  esac\n}\n\n[[ $# -ne 1 ]] && error 1\n[[ $1 =~ ^[0-9]+$ ]] || error 2\n\nduration=${1}\nbarsize=$((`tput cols` - 7))\nunity=$(($barsize / $duration))\nincrement=$(($barsize%$duration))\nskip=$(($duration/($duration-$increment)))\ncurr_bar=0\nprev_bar=\nfor (( elapsed=1; elapsed<=$duration; elapsed++ ))\ndo\n  # Elapsed\nprev_bar=$curr_bar\n  let curr_bar+=$unity\n  [[ $increment -eq 0 ]] || {  \n    [[ $skip -eq 1 ]] &&\n      { [[ $(($elapsed%($duration/$increment))) -eq 0 ]] && let curr_bar++; } ||\n    { [[ $(($elapsed%$skip)) -ne 0 ]] && let curr_bar++; }\n  }\n  [[ $elapsed -eq 1 && $increment -eq 1 && $skip -ne 1 ]] && let curr_bar++\n  [[ $(($barsize-$curr_bar)) -eq 1 ]] && let curr_bar++\n  [[ $curr_bar -lt $barsize ]] || curr_bar=$barsize\n  for (( filled=0; filled<=$curr_bar; filled++ )); do\n    printf "\xe2\x96\x87"\n  done\n\n  # Remaining\n  for (( remain=$curr_bar; remain<$barsize; remain++ )); do\n    printf " "\n  done\n\n  # Percentage\n  printf "| %s%%" $(( ($elapsed*100)/$duration))\n\n  # Return\n  sleep 1\n  printf "\\r"\ndone\nprintf "\\n"\nexit 0\n
Run Code Online (Sandbox Code Playgroud)\n\n

享受

\n


pol*_*lle 5

APT样式进度条(不中断正常输出)

在此处输入图片说明

编辑:有关更新的版本,请检查我的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
Run Code Online (Sandbox Code Playgroud)

脚本(我强烈建议在我的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}"
}
Run Code Online (Sandbox Code Playgroud)


Win*_*nix 5

我需要一个适合弹出气泡消息 ( notify-send) 的进度条来表示电视音量级别。最近我一直在用python写一个音乐播放器,电视画面大部分时间都是关闭的。

\n

终端输出示例

\n

test_progress_bar3.gif

\n
\n

bash脚本

\n
#!/bin/bash\n\n# Show a progress bar at step number $1 (from 0 to 100)\n\n\nfunction is_int() { test "$@" -eq "$@" 2> /dev/null; } \n\n# Parameter 1 must be integer\nif ! is_int "$1" ; then\n   echo "Not an integer: ${1}"\n   exit 1\nfi\n\n# Parameter 1 must be >= 0 and <= 100\nif [ "$1" -ge 0 ] && [ "$1" -le 100 ]  2>/dev/null\nthen\n    :\nelse\n    echo bad volume: ${1}\n    exit 1\nfi\n\n# Main function designed for quickly copying to another program \nMain () {\n\n    Bar=""                      # Progress Bar / Volume level\n    Len=25                      # Length of Progress Bar / Volume level\n    Div=4                       # Divisor into Volume for # of blocks\n    Fill="\xe2\x96\x92"                    # Fill up to $Len\n    Arr=( "\xe2\x96\x89" "\xe2\x96\x8e" "\xe2\x96\x8c" "\xe2\x96\x8a" )     # UTF-8 left blocks: 7/8, 1/4, 1/2, 3/4\n\n    FullBlock=$((${1} / Div))   # Number of full blocks\n    PartBlock=$((${1} % Div))   # Size of partial block (array index)\n\n    while [[ $FullBlock -gt 0 ]]; do\n        Bar="$Bar${Arr[0]}"     # Add 1 full block into Progress Bar\n        (( FullBlock-- ))       # Decrement full blocks counter\n    done\n\n    # If remainder zero no partial block, else append character from array\n    if [[ $PartBlock -gt 0 ]]; then\n        Bar="$Bar${Arr[$PartBlock]}"\n    fi\n\n    while [[ "${#Bar}" -lt "$Len" ]]; do\n        Bar="$Bar$Fill"         # Pad Progress Bar with fill character\n    done\n\n    echo Volume: "$1 $Bar"\n    exit 0                      # Remove this line when copying into program\n} # Main\n\nMain "$@"\n
Run Code Online (Sandbox Code Playgroud)\n
\n

测试 bash 脚本

\n

使用此脚本测试终端中的进度条。

\n
#!/bin/bash\n\n# test_progress_bar3\n\nMain () {\n\n    tput civis                              # Turn off cursor\n    for ((i=0; i<=100; i++)); do\n        CurrLevel=$(./progress_bar3 "$i")   # Generate progress bar 0 to 100\n        echo -ne "$CurrLevel"\\\\r            # Reprint overtop same line\n        sleep .04\n    done\n    echo -e \\\\n                             # Advance line to keep last progress\n    echo "$0 Done"\n    tput cnorm                              # Turn cursor back on\n} # Main\n\nMain "$@"\n
Run Code Online (Sandbox Code Playgroud)\n
\n

长话短说

\n

本节详细介绍如何notify-send使用快速向桌面发送垃圾弹出气泡消息。这是必需的,因为音量级别每秒可能会改变多次,并且默认的气泡消息行为是消息在桌面上停留很多秒。

\n

弹出气泡消息示例

\n

电视供电.gif

\n

弹出气泡消息bash代码

\n

从上面的脚本中,该main函数被复制到一个名为 的VolumeBar现有 bash 脚本中调用的新函数tvpoweredexit 0复制的函数中的命令已main被删除。

\n

以下是如何调用它并让 Ubuntu 的notify-send命令知道我们将发送垃圾邮件弹出气泡消息:

\n
VolumeBar $CurrVolume\n# Ask Ubuntu: https://askubuntu.com/a/871207/307523\nnotify-send --urgency=critical "tvpowered" \\\n    -h string:x-canonical-private-synchronous:volume \\\n    --icon=/usr/share/icons/gnome/48x48/devices/audio-speakers.png \\\n    "Volume: $CurrVolume $Bar"\n
Run Code Online (Sandbox Code Playgroud)\n

这是新行,指示notify-send立即替换最后一个弹出气泡:

\n
-h string:x-canonical-private-synchronous:volume \\\n
Run Code Online (Sandbox Code Playgroud)\n

volume将弹出的气泡消息分组在一起,该组中的新消息立即替换之前的消息。您可以使用anything代替volume.

\n