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

例如,复制一个大文件,打开一个大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提到,如果您以长行开始,然后想要编写短行,那么这种方法“失败”:在这种情况下,您将需要覆盖长行的长度(例如,使用空格)。

其他回答

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

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

$ tar -c --checkpoint=1000 --checkpoint-action=dot /var
...

同样的效果可以通过:

$ tar -c --checkpoint=.1000 /var

你可能也对如何做一个旋转器感兴趣:

我能在Bash中做旋转吗?

Sure! i=1 sp="/-\|" echo -n ' ' while true do printf "\b${sp:i++%${#sp}:1}" done Each time the loop iterates, it displays the next character in the sp string, wrapping around as it reaches the end. (i is the position of the current character to display and ${#sp} is the length of the sp string). The \b string is replaced by a 'backspace' character. Alternatively, you could play with \r to go back to the beginning of the line. If you want it to slow down, put a sleep command inside the loop (after the printf). A POSIX equivalent would be: sp='/-\|' printf ' ' while true; do printf '\b%.1s' "$sp" sp=${sp#?}${sp%???} done If you already have a loop which does a lot of work, you can call the following function at the beginning of each iteration to update the spinner: 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

首先,杆并不是唯一的管道进度仪表。另一个(可能更广为人知)是pv(管道查看器)。

其次,bar和pv可以这样使用:

$ bar file1 | wc -l 
$ pv file1 | wc -l

甚至:

$ tail -n 100 file1 | bar | wc -l
$ tail -n 100 file1 | pv | wc -l

如果你想在命令中使用bar和pv来处理参数中给出的文件,比如copy file1 file2,一个有用的技巧是使用进程替换:

$ copy <(bar file1) file2
$ copy <(pv file1) file2

进程替换是bash的一个神奇的东西,它创建临时fifo管道文件/dev/fd/,并通过该管道连接运行进程(括号内)的stdout,复制看到它就像一个普通文件一样(只有一个例外,它只能向前读取)。

更新:

Bar命令本身也允许复制。男子酒吧后:

bar --in-file /dev/rmt/1cbn --out-file \
     tape-restore.tar --size 2.4g --buffer-size 64k

但是在我看来,过程替换是更通用的方法。它本身使用cp程序。

关于这个主题有很多不同的答案,但是当计算文本文件操作的百分比时,使用当前长度/总大小的方式,例如显示ver_big_file的百分比。我建议使用awk来实现这个目的,如下所示:

awk '
    function bar(x){s="";i=0;while (i++ < x) s=s "#";return s}
    BEGIN{
        ("ls -l " ARGV[1]) | getline total;
        split(total,array);
        total=array[5];
    }
    {
        cur+=length($0)+1;
        percent=int(cur / total * 100);
        printf "LINE %s:%s %s%%\r", NR, bar(percent*.8), percent 
    }
    END {print}' very_big_file.json | grep "keyword" | ...

这种方法非常精确,基于流,但只适用于文本文件。

在我的系统上使用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