当在bash或*NIX中的任何其他shell中编写脚本时,在运行需要超过几秒钟时间的命令时,需要一个进度条。
例如,复制一个大文件,打开一个大tar文件。
你建议用什么方法向shell脚本添加进度条?
当在bash或*NIX中的任何其他shell中编写脚本时,在运行需要超过几秒钟时间的命令时,需要一个进度条。
例如,复制一个大文件,打开一个大tar文件。
你建议用什么方法向shell脚本添加进度条?
当前回答
我想根据命令输出的行数和之前运行的目标行数来跟踪进度:
#!/bin/bash
function lines {
local file=$1
local default=$2
if [[ -f $file ]]; then
wc -l $file | awk '{print $1}';
else
echo $default
fi
}
function bar {
local items=$1
local total=$2
local size=$3
percent=$(($items*$size/$total % $size))
left=$(($size-$percent))
chars=$(local s=$(printf "%${percent}s"); echo "${s// /=}")
echo -ne "[$chars>";
printf "%${left}s"
echo -ne ']\r'
}
function clearbar {
local size=$1
printf " %${size}s "
echo -ne "\r"
}
function progress {
local pid=$1
local total=$2
local file=$3
bar 0 100 50
while [[ "$(ps a | awk '{print $1}' | grep $pid)" ]]; do
bar $(lines $file 0) $total 50
sleep 1
done
clearbar 50
wait $pid
return $?
}
然后这样使用它:
target=$(lines build.log 1000)
(mvn clean install > build.log 2>&1) &
progress $! $target build.log
它输出一个进度条,看起来像这样:
[===============================================> ]
条形图随着输出行数达到目标而增长。如果行数超过了目标,条就重新开始(希望目标是好的)。
BTW:我在Mac OSX上使用bash。我基于这个代码从mariascio旋转。
其他回答
这只适用于使用地精天顶。Zenity为bash脚本提供了一个很棒的本机界面: https://help.gnome.org/users/zenity/stable/
来自Zenity进度条示例:
#!/bin/sh
(
echo "10" ; sleep 1
echo "# Updating mail logs" ; sleep 1
echo "20" ; sleep 1
echo "# Resetting cron jobs" ; sleep 1
echo "50" ; sleep 1
echo "This line will just be ignored" ; sleep 1
echo "75" ; sleep 1
echo "# Rebooting system" ; sleep 1
echo "100" ; sleep 1
) |
zenity --progress \
--title="Update System Logs" \
--text="Scanning mail logs..." \
--percentage=0
if [ "$?" = -1 ] ; then
zenity --error \
--text="Update canceled."
fi
你可能也对如何做一个旋转器感兴趣:
我能在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
这可以通过一种相当简单的方式来实现:
使用for循环从0迭代到100 每一步睡眠25毫秒(0.25秒) 在$bar变量后面附加另一个=号,使进度条变宽 返回进度条和百分比(\r清除行并返回行首;-ne使echo在结尾不添加换行符,并解析\r特殊字符)
function progress {
bar=''
for (( x=0; x <= 100; x++ )); do
sleep 0.25
bar="${bar}="
echo -ne "$bar ${x}%\r"
done
echo -e "\n"
}
$ progress
> ========== 10% # here: after 2.5 seconds
$ progress
> ============================== 30% # here: after 7.5 seconds
彩色进度条
function progress {
bar=''
for (( x=0; x <= 100; x++ )); do
sleep 0.05
bar="${bar} "
echo -ne "\r"
echo -ne "\e[43m$bar\e[0m"
local left="$(( 100 - $x ))"
printf " %${left}s"
echo -n "${x}%"
done
echo -e "\n"
}
要使进度条变得彩色,你可以使用格式化转义序列-这里进度条是黄色的:\e[43m,然后我们用\e[0m重置自定义设置,否则即使进度条完成了,它也会影响进一步的输入。
一些帖子已经展示了如何显示命令的进度。为了计算它,你需要看看你已经进步了多少。在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脚本的早期版本出现在我的博客上(“在Unix上监视进程进度”)。
前几天我写了一个简单的进度条函数:
#!/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/