Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

getopts won't call twice in a row? [duplicate]

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;
like image 354
ParoX Avatar asked Feb 19 '11 01:02

ParoX


People also ask

What does colon mean in getopts?

An option character in this string can be followed by a colon (' : ') to indicate that it takes a required argument. If an option character is followed by two colons (' :: '), its argument is optional; this is a GNU extension. getopt has three ways to deal with options that follow non-options argv elements.

What is Optind in getopts?

According to man getopts , OPTIND is the index of the next argument to be processed (starting index is 1). Hence, In sh foo.sh -abc CCC Blank arg1 is -abc , so after a we are still parsing arg1 when next is b ( a 1 ).

What does getopts mean in Bash?

Updated: 02/01/2021 by Computer Hope. On Unix-like operating systems, getopts is a builtin command of the Bash shell. It parses command options and arguments, such as those passed to a shell script.

Which of these is a difference between getopt and getopts?

getopt vs getopts The main differences between getopts and getopt are as follows: getopt does not handle empty flag arguments well; getopts does. getopts is included in the Bourne shell and Bash; getopt needs to be installed separately.


2 Answers

Just add:

local OPTIND

at the top of your function.

like image 143
Dennis Williamson Avatar answered Nov 02 '22 10:11

Dennis Williamson


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.

like image 14
Mikel Avatar answered Nov 02 '22 09:11

Mikel