当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《如何向shell脚本添加进度条?》经验,为你挑选了13个好方法。

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

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

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



1> Mitch Haile..:

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

2> Daenyth..:

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

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

当然!

i=1
sp="/-\|"
echo -n ' '
while true
do
    printf "\b${sp:i++%${#sp}:1}"
done

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

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

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

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`可能需要整数而不是小数)

3> Diomidis Spi..:

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

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

$ pmonitor -c gzip
/home/dds/data/mysql-2015-04-01.sql.gz 58.06%

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



4> 小智..:

使用linux命令pv:

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

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



5> 小智..:

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

#!/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/



6> Édouard Lope..:

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

预习

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
}

用法

 progress-bar 100



7> 小智..:

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

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

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

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

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



8> 小智..:

一种更简单的方法,可以使用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



9> 小智..:

我还想贡献自己的进度条

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

在此输入图像描述

代码包括在内



10> cprn..:

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

#!/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} - 最后没有新行打印

echo -n - 打印时解释特殊字符

echo -e - 回车,返回行首的特殊字符

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



11> 小智..:

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

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

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



12> Vagiz Duseev..:

这是它的外观

上载档案

[##################################################] 100% (137921 / 137921 bytes)

等待工作完成

[#########################                         ] 50% (15 / 30 seconds)

实现它的简单功能

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

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"
}

使用范例

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

在下面的示例中,最大值为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"



13> polle..:

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

脚本(我强烈建议在我的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}"
}

推荐阅读
喜生-Da
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有