如何使用 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
whiptail
预装在 Ubuntu 和许多其他发行版上,并将显示全屏(但仍然基于终端)的进度元素。
dialog
是 的超集whiptail
,因此本示例对两者都同样适用。它确实提供了更高级的 UI 元素,因此如果您正在寻找文件选择器和表单等用户交互,它可能会派上用场,但它的缺点是许多系统上没有预装。
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 脚本可以添加该功能,正如其他人在这里分享的那样。
答案2
您可以使用它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
。手动的:您必须将当前进度百分比通过管道传输到
zenity
命令的标准输入以更新进度条。
此示例如下所示。请注意,前面的命令被分组到子 shell 中,以便所有输出都重定向到对话框zenity
,而不仅仅是最后一个命令的输出:(echo 10; sleep 2; echo 20; sleep 2; echo 50; sleep 2) | zenity --progress
答案3
这段代码可以完成这个任务,并且不需要任何东西(当然,除了 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
将第一行 ( ) 中的 5 更改lenProgressBar=5
为您想要的进度条长度。与#
长度较长的进度条相比,长度较短的进度条打印标志所需的时间更长,但不要让进度条的长度超过您的屏幕尺寸;如果超过,效果会不好。(它不允许您使用高于您正在检查的项目数或低于 1 的进度条)
答案4
从堆栈溢出
我需要一个适合弹出气泡消息 ( notify-send
) 的进度条来表示电视音量级别。最近我一直在用 Python 编写音乐播放器,电视画面大部分时间都是关闭的。
终端输出示例
Bash 脚本
#!/bin/bash
# Show a progress bar at step number $1 (from 0 to 100)
function is_int() { test "$@" -eq "$@" 2> /dev/null; }
# Parameter 1 must be integer
if ! is_int "$1" ; then
echo "Not an integer: ${1}"
exit 1
fi
# Parameter 1 must be >= 0 and <= 100
if [ "$1" -ge 0 ] && [ "$1" -le 100 ] 2>/dev/null
then
:
else
echo bad volume: ${1}
exit 1
fi
# Main function designed for quickly copying to another program
Main () {
Bar="" # Progress Bar / Volume level
Len=25 # Length of Progress Bar / Volume level
Div=4 # Divisor into Volume for # of blocks
Fill="▒" # Fill up to $Len
Arr=( "▉" "▎" "▌" "▊" ) # UTF-8 left blocks: 7/8, 1/4, 1/2, 3/4
FullBlock=$((${1} / Div)) # Number of full blocks
PartBlock=$((${1} % Div)) # Size of partial block (array index)
while [[ $FullBlock -gt 0 ]]; do
Bar="$Bar${Arr[0]}" # Add 1 full block into Progress Bar
(( FullBlock-- )) # Decrement full blocks counter
done
# If remainder zero no partial block, else append character from array
if [[ $PartBlock -gt 0 ]]; then
Bar="$Bar${Arr[$PartBlock]}"
fi
while [[ "${#Bar}" -lt "$Len" ]]; do
Bar="$Bar$Fill" # Pad Progress Bar with fill character
done
echo Volume: "$1 $Bar"
exit 0 # Remove this line when copying into program
} # Main
Main "$@"
测试 bash 脚本
使用此脚本测试终端中的进度条。
#!/bin/bash
# test_progress_bar3
Main () {
tput civis # Turn off cursor
for ((i=0; i<=100; i++)); do
CurrLevel=$(./progress_bar3 "$i") # Generate progress bar 0 to 100
echo -ne "$CurrLevel"\\r # Reprint overtop same line
sleep .04
done
echo -e \\n # Advance line to keep last progress
echo "$0 Done"
tput cnorm # Turn cursor back on
} # Main
Main "$@"
总结
本节详细介绍了如何notify-send
使用 来快速向桌面发送弹出气泡消息。这是必需的,因为音量级别每秒可以改变多次,并且默认的气泡消息行为是消息在桌面上停留数秒。
弹出气泡消息示例
弹出气泡消息 bash 代码
从上面的脚本中,将函数复制到现有 bash 脚本中main
名为 的新函数中。复制函数中的命令已被删除。VolumeBar
tvpowered
exit 0
main
以下是如何调用它并让 Ubuntu 的notify-send
命令知道我们将发送弹出气泡消息:
VolumeBar $CurrVolume
# Ask Ubuntu: https://askubuntu.com/a/871207/307523
notify-send --urgency=critical "tvpowered" \
-h string:x-canonical-private-synchronous:volume \
--icon=/usr/share/icons/gnome/48x48/devices/audio-speakers.png \
"Volume: $CurrVolume $Bar"
这是新行,指示notify-send
立即替换最后一个弹出气泡:
-h string:x-canonical-private-synchronous:volume \
volume
将弹出气泡消息分组在一起,此组中的新消息立即替换前一个。您可以使用anything
代替volume
。