问题
For some reason the options work fine the first call of lib_progress_bar -c "@" -u "_" 0 100
, but on the second call and beyond everything is default because it seems like getopts c:u:d:p:s:%:m: flag
isn't true the second time around, or atleast the case is never executed when I used set -x
#!/bin/bash
lib_progress_bar() {
local current=0
local max=100
local completed_char="#"
local uncompleted_char="."
local decimal=1
local prefix=" ["
local suffix="]"
local percent_sign="%"
local max_width=$(tput cols)
local complete remain subtraction width atleast percent chars
local padding=3
while getopts c:u:d:p:s:%:m: flag; do
case "$flag" in
c) completed_char="$OPTARG";;
u) uncompleted_char="$OPTARG";;
d) decimal="$OPTARG";;
p) prefix="$OPTARG";;
s) suffix="$OPTARG";;
%) percent_sign="$OPTARG";;
m) max_width="$OPTARG";;
esac
done
shift $((OPTIND-1))
current=${1:-$current}
max=${2:-$max}
if (( decimal > 0 )); then
(( padding = padding + decimal + 1 ))
fi
let subtraction=${#completed_char}+${#prefix}+${#suffix}+padding+${#percent_sign}
let width=max_width-subtraction
if (( width < 5 )); then
(( atleast = 5 + subtraction ))
echo >&2 "the max_width of ($max_width) is too small, must be atleast $atleast"
return 1
fi
if (( current > max ));then
echo >&2 "current value must be smaller than max. value"
return 1
fi
percent=$(awk -v "f=%${padding}.${decimal}f" -v "c=$current" -v "m=$max" 'BEGIN{printf('f', c / m * 100)}')
(( chars = current * width / max))
# sprintf n zeros into the var named as the arg to -v
printf -v complete '%0*.*d' '' "$chars" ''
printf -v remain '%0*.*d' '' "$((width - chars))" ''
# replace the zeros with the desired char
complete=${complete//0/"$completed_char"}
remain=${remain//0/"$uncompleted_char"}
printf '%s%s%s%s %s%s\r' "$prefix" "$complete" "$remain" "$suffix" "$percent" "$percent_sign"
if (( current >= max )); then
echo ""
fi
}
lib_progress_bar -c "@" -u "_" 0 100
echo
lib_progress_bar -c "@" -u "_" 25 100
echo
lib_progress_bar -c "@" -u "_" 50 100
echo
exit;
回答1:
Just add:
local OPTIND
at the top of your function.
回答2:
To explain why Dennis's answer works, see the bash
man page (search for getopts
):
OPTIND is initialized to 1 each time the shell or a shell script is invoked.
The shell does not reset OPTIND automatically; it must be manually reset between multiple calls to getopts within the same shell invocation if a new set of parameters is to be used.
This is how getopts
can process multiple options.
If getopts
didn't maintain global state in the OPTIND
variable, each call to getopts
in your while
loop would keep processing $1
, and never advance to the next argument.
来源:https://stackoverflow.com/questions/5048326/getopts-wont-call-twice-in-a-row