在bash中创建进度条


13

如何使用bash创建进度栏?

这是我的脚本:

 #!/bin/bash
 pass='number1 number12 number13 number14 number15 number16'
 chk='number14'
 for i in $pass ; do
 if [ "$i" == "$chk" ]; then
 echo ' Found ^_^'
 else
 echo 'loading 50%'
 fi
 done

我想替换echo 'loading 50%'为创建进度条的任何内容。


1
终端中的进度条还是单独的GUI窗口中的进度条?
字节指挥官

2
在航站楼
黑鹰

eta可以做你想做的。
aioobe

Answers:


14

whiptail 预先安装在Ubuntu和许多其他发行版中,并将显示全屏(但仍基于终端)进度元素。

dialog是的超集whiptail,因此此示例对两者都适用。它确实提供了更高级的UI元素,因此,如果您正在寻找诸如文件选择器和表单之类的用户交互功能,它可能会派上用场,但是它的缺点是没有预先安装在许多系统上。

ip

对话

for i in $(seq 1 100)
do
    sleep 0.1 
    echo $i
done | whiptail --title 'Test script' --gauge 'Running...' 6 60 0

请注意,脚本输出解释为百分比,因此您可能必须相应地调整输出。

Whiptail和Dialog还允许您在运行时通过相当隐秘的语法来修改文本:

phases=( 
    'Locating Jebediah Kerman...'
    'Motivating Kerbals...'
    'Treating Kessler Syndrome...'
    'Recruiting Kerbals...'
)   

for i in $(seq 1 100); do  
    sleep 0.1

    if [ $i -eq 100 ]; then
        echo -e "XXX\n100\nDone!\nXXX"
    elif [ $(($i % 25)) -eq 0 ]; then
        let "phase = $i / 25"
        echo -e "XXX\n$i\n${phases[phase]}\nXXX"
    else
        echo $i
    fi 
done | whiptail --title 'Kerbal Space Program' --gauge "${phases[0]}" 6 60 0

pv显示通过文件传递的文件或流的进度。但是,它不能(轻松地?)用于显示自定义操作(例如循环)的进度。专为流而设计。

$ head -c 1G < /dev/urandom | pv -s 1G > /dev/null
 277MB 0:00:16 [17.4MB/s] [========>                           ] 27% ETA 0:00:43

方便使用的一些实际示例pv

# progress while importing a DB dump
pv mybigfile.sql | mysql -uroot -p dbname

# importing straight from a remote server
ssh user@server 'cat mybigfile.sql.gz' | pv | gzip -cd | mysql -uroot -p dbname

# taking a snapshot of a btrfs partition
btrfs send /snapshots/$date | pv | btrfs receive /mnt/backup/root

我不知道任何以pv或样式提供单行进度条的命令wget,但是有很多简单的Bash / Perl / sed脚本可以添加该功能,其他人在这里也分享过。


要显示一个循环的过程,pv可以使它寻找循环的输出,也可以创建一些伪造的输出,例如,echo在每次迭代中将管道输送到,pv并使用为其提供迭代计数-s。如果不需要,请记住将循环的标准输出重定向到/dev/null这是显示此方法的示例
甜点

6

您可以zenity用来创建简单的GTK对话框窗口。可用选项之一是进度条对话框。

您可以使用创建此类窗口zenity --progress。为了使它有用,您应该通过添加以下一些选项(摘录自man zenity)来指定更多信息:

   Progress options
   --text=STRING
          Set the dialog text
   --percentage=INT
          Set initial percentage
   --auto-close
          Close dialog when 100% has been reached
   --auto-kill
          Kill parent process if cancel button is pressed
   --pulsate
          Pulsate progress bar
   --no-cancel
          Hides the cancel button

有两种模式:

  • 搏动:进度条在搏动,仅表示正在运行,但不告诉任何进度。您可以通过设置--pulsating选项来实现。

  • manual:您必须将当前进度百分比传递到zenity命令的标准输入以更新进度栏。
    一个示例如下所示。请注意,前面的命令被分组到一个子外壳中,以便所有输出都重定向到zenity对话框,而不仅仅是上一个命令:

    (echo 10; sleep 2; echo 20; sleep 2; echo 50; sleep 2) | zenity --progress

万一这也是一种选择。
字节指挥官

1
抱歉,亲爱的,这是GUI进度栏窗口,我想在终端中创建进度栏,例如,我想在脚本检查==>时看到它[ ###########--------------] 52%
Black Hawk

1
是的我明白。只是您说完这些后,我已经写了一半的答案,因此我决定还是将其发布,以防将来有人需要。希望您不要介意,因为还有很多基于终端的解决方案。
字节指挥官

5

这段代码可以做到,不需要任何东西(当然,除了bash之外)。#像您在评论中要求的那样,它会打印标志:

pass='number1 number12 number13 number14 number15 number16'
chk='number14'
passarr=($pass)
lenProgressBar=${#passarr[@]}

echo -n '['
i=0

while [ $i -lt $lenProgressBar ]; do
    echo -n '-'
    ((i++))
done

echo -n ']'
i=0

while [ $i -lt $lenProgressBar ]; do
    echo -e -n '\b'
    ((i++))
done

echo -e -n '\b'
for i in $pass ; do
    if [ "$i" = "$chk" ]; then
        echo -e '#\nFound ^_^'
        break
    else
        echo -n '#'
    fi
done

但是,如果您要检查的东西很多,这只会在屏幕上充满#标志。要解决该问题,请尝试以下代码:

lenProgressBar=5
pass='number1 number12 number13 number14 number15 number16'
chk='number14'
passarr=($pass)
lenPass=${#passarr[@]}

if [ $lenProgressBar -gt $lenPass ]; then
    lenProgressBar=lenPass
elif [ $lenProgressBar -lt 1 ]; then
    lenProgressBar=1
fi

let "chksForEqualsPrint = $lenPass / $lenProgressBar"
echo -n '['
i=0

while [ $i -lt $lenProgressBar ]; do
    echo -n '-'
    ((i++))
done

echo -n ']'
i=0

while [ $i -lt $lenProgressBar ]; do
    echo -e -n '\b'
    ((i++))
done

echo -e -n '\b'
n=1

for i in $pass ; do
    if [ "$i" = "$chk" ]; then
        echo -e '\nFound ^_^'
        break
    else
        if [ $n -eq $chksForEqualsPrint ]; then
            echo -n '#'
            n=1
        else
            ((n++))
        fi
    fi
done

将第一行(lenProgressBar=5)中的5更改为您希望进度条的长度。#使用长度较小的进度条打印标志的时间要比长度较长的标志打印时间更长,但是不要让进度条的长度超过屏幕尺寸。如果这样做,它将无法正常工作。(它不允许您使用进度条大于要检查的项目数或小于1)


1
您可以tput cols用来检测终端窗口的宽度并相应地缩放进度条。
米克尔

1

这是使用ansi转义码的另一种方法:

#!/bin/bash

pass='number1 number2 number 3 number4 number12 number13 number14 number15 number16'
chk='number15'
result="Not Found!"

echo
echo -n "Working... "
echo -ne "\033[1;32m\033[7m\033[?25l"

for i in $pass ; do
   sleep .4s
   if [ "$i" == "$chk" ]; then
      result="  Found ^_^"
      break
   else
      echo -n " "
   fi
done

echo -ne "\r\033[0m\033[K\033[?25h"
echo $result
echo
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.