2011-02-19 22 views
12

Por alguna razón las opciones funcionan bien la primera llamada de lib_progress_bar -c "@" -u "_" 0 100, pero en la segunda llamada y más allá todo está predeterminado porque parece que getopts c:u:d:p:s:%:m: flag no es verdad la segunda vez, o al menos la caja nunca se ejecuta cuando usé set -xgetopts no llamará dos veces seguidas?

#!/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; 

Respuesta

14

Sólo añadir:

local OPTIND 

en la parte superior de su función.

+0

"OPTIND = 1" también funciona. –

+0

Utilizo 'OPTIND = 0' después de mis getopts-while-loop y shift. No sabía sobre el truco 'local OPTIND', pero el reinicio cero debería funcionar si estás extrañamente llamando' getopts' más de una vez en la _mása función_. –

13

Para explicar por qué funciona la respuesta de Dennis, ver la página bash hombre (búsqueda de getopts):

OPTIND se inicializa a 1 cada vez que se invoca la cáscara o una secuencia de comandos shell.

El shell no reinicia OPTIND automáticamente; debe restablecerse manualmente entre varias llamadas a getopts dentro de la misma invocación de shell si se va a utilizar un nuevo conjunto de parámetros.

Así es como getopts puede procesar múltiples opciones.

Si getopts no mantienen el estado global en la variable OPTIND, cada llamada a getopts en su bucle while mantendría procesamiento $1, y nunca avanzar al siguiente argumento.

Cuestiones relacionadas