traduccion script bash command-line-arguments getopts

traduccion - bash script



¿Cómo puedo usar opciones largas con el Bash getopts incorporado? (7)

Aunque esta pregunta se publicó hace más de 2 años, me encontré necesitando soporte para opciones largas al estilo XFree86; Y también quería tomar lo que pudiera de getopts. Considere el interruptor GCC - -rdynamic . Marque r como la letra de la bandera, y espero dynamic dentro de $OPTARG ... pero, quiero rechazar -r dynamic , al mismo tiempo que acepto otras opciones después de r .

La idea que he puesto a continuación se basa en la observación de que $OPTIND será uno más grande que de otra manera si el espacio (un espacio) sigue la bandera. Entonces, defino una variable bash para mantener el valor anterior de $OPTIND , llamado $PREVOPTIND , y lo actualizo al final del ciclo while. Si $OPTIND es 1 mayor que $PREVOPTIND , no tenemos espacio (es decir, -rdynamic ); y $GAP se establece en false . Si, en cambio, $OPTIND es 2 mayor que $PREVOPTIND , tenemos un espacio (por ejemplo, -r dynamic ), y $GAP se establece en true .

usage() { echo usage: error from $1; exit -1; } OPTIND=1 PREVOPTIND=$OPTIND while getopts "t:s:o:" option; do GAP=$((OPTIND-(PREVOPTIND+1))) case $option in t) case "${OPTARG}" in emp) # i.e. -temp ((GAP)) && usage "-${option} and ${OPTARG}" TMPDIR="$OPTARG" ;; *) true ;; esac ;; s) case "${OPTARG}" in hots) # i.e. -shots ((GAP)) && usage NUMSHOTS="$OPTARG" ;; *) usage "-${option} and ${OPTARG}" ;; esac ;; o) OUTFILE="$OPTARG" ;; *) usage "-${option} and ${OPTARG}" ;; esac PREVOPTIND=$OPTIND done shift $(($OPTIND - 1))

Estoy tratando de analizar una opción -temp con Bash getopts. Estoy llamando a mi guión así:

./myscript -temp /foo/bar/someFile

Aquí está el código que estoy usando para analizar las opciones.

while getopts "temp:shots:o:" option; do case $option in temp) TMPDIR="$OPTARG" ;; shots) NUMSHOTS="$OPTARG" ;; o) OUTFILE="$OPTARG" ;; *) usage ;; esac done shift $(($OPTIND - 1)) [ $# -lt 1 ] && usage


Como explicaron otras personas, Getopts no analiza opciones largas. Puedes usar getopt, pero no es portátil (y está roto en alguna plataforma ...)

Como solución alternativa, puede implementar un bucle de shell. Aquí un ejemplo que transforma las opciones largas en opciones cortas antes de usar el comando estándar getopts (es más simple en mi opinión):

# Transform long options to short ones for arg in "$@"; do shift case "$arg" in "--help") set -- "$@" "-h" ;; "--rest") set -- "$@" "-r" ;; "--ws") set -- "$@" "-w" ;; *) set -- "$@" "$arg" esac done # Default behavior rest=false; ws=false # Parse short options OPTIND=1 while getopts "hrw" opt do case "$opt" in "h") print_usage; exit 0 ;; "r") rest=true ;; "w") ws=true ;; "?") print_usage >&2; exit 1 ;; esac done shift $(expr $OPTIND - 1) # remove options from positional parameters


Es cierto que las getopts bash getopts solo analizan opciones cortas, pero aún puede agregar algunas líneas de scripting para que getopts maneje opciones largas.

Aquí hay una parte del código que se encuentra en http://www.uxora.com/unix/shell-script/22-handle-long-options-with-getopts

#== set options ==# SCRIPT_OPTS='':fbF:B:-:h'' typeset -A ARRAY_OPTS ARRAY_OPTS=( [foo]=f [bar]=b [foobar]=F [barfoo]=B [help]=h [man]=h ) #== parse options ==# while getopts ${SCRIPT_OPTS} OPTION ; do #== translate long options to short ==# if [[ "x$OPTION" == "x-" ]]; then LONG_OPTION=$OPTARG LONG_OPTARG=$(echo $LONG_OPTION | grep "=" | cut -d''='' -f2) LONG_OPTIND=-1 [[ "x$LONG_OPTARG" = "x" ]] && LONG_OPTIND=$OPTIND || LONG_OPTION=$(echo $OPTARG | cut -d''='' -f1) [[ $LONG_OPTIND -ne -1 ]] && eval LONG_OPTARG="/$$LONG_OPTIND" OPTION=${ARRAY_OPTS[$LONG_OPTION]} [[ "x$OPTION" = "x" ]] && OPTION="?" OPTARG="-$LONG_OPTION" if [[ $( echo "${SCRIPT_OPTS}" | grep -c "${OPTION}:" ) -eq 1 ]]; then if [[ "x${LONG_OPTARG}" = "x" ]] || [[ "${LONG_OPTARG}" = -* ]]; then OPTION=":" OPTARG="-$LONG_OPTION" else OPTARG="$LONG_OPTARG"; if [[ $LONG_OPTIND -ne -1 ]]; then [[ $OPTIND -le $Optnum ]] && OPTIND=$(( $OPTIND+1 )) shift $OPTIND OPTIND=1 fi fi fi fi #== options follow by another option instead of argument ==# if [[ "x${OPTION}" != "x:" ]] && [[ "x${OPTION}" != "x?" ]] && [[ "${OPTARG}" = -* ]]; then OPTARG="$OPTION" OPTION=":" fi #== manage options ==# case "$OPTION" in f ) foo=1 bar=0 ;; b ) foo=0 bar=1 ;; B ) barfoo=${OPTARG} ;; F ) foobar=1 && foobar_name=${OPTARG} ;; h ) usagefull && exit 0 ;; : ) echo "${SCRIPT_NAME}: -$OPTARG: option requires an argument" >&2 && usage >&2 && exit 99 ;; ? ) echo "${SCRIPT_NAME}: -$OPTARG: unknown option" >&2 && usage >&2 && exit 99 ;; esac done shift $((${OPTIND} - 1))

Aquí hay una prueba:

# Short options test $ ./foobar_any_getopts.sh -bF "Hello world" -B 6 file1 file2 foo=0 bar=1 barfoo=6 foobar=1 foobar_name=Hello world files=file1 file2 # Long and short options test $ ./foobar_any_getopts.sh --bar -F Hello --barfoo 6 file1 file2 foo=0 bar=1 barfoo=6 foobar=1 foobar_name=Hello files=file1 file2

De lo contrario, en el reciente Korn Shell ksh93, getopts puede analizar naturalmente opciones largas e incluso mostrar una página de manual por igual. (vea http://www.uxora.com/unix/shell-script/20-getopts-with-man-page-and-long-options )

Michel VONGVILAY.


Gracias a @mcoolive.

Pude usar su idea $ @ para convertir opciones de palabra completa y larga en opciones de una sola letra. Quería notarle a cualquiera que utilizara esta idea que también tenía que incluir shift $(expr $OPTIND - 1) antes de ejecutar los argumentos a través del bucle getopts.

Propósito totalmente diferente pero esto está funcionando bien.

# convert long word options to short word for ease of use and portability for argu in "$@"; do shift #echo "curr arg = $1" case "$argu" in "-start"|"--start") # param=param because no arg is required set -- "$@" "-s" ;; "-pb"|"--pb"|"-personalbrokers"|"--personalbrokers") # pb +arg required set -- "$@" "-p $1"; #echo "arg=$argu" ;; "-stop"|"--stop") # param=param because no arg is required set -- "$@" "-S" ;; # the catch all option here removes all - symbols from an # argument. if an option is attempted to be passed that is # invalid, getopts knows what to do... *) [[ $(echo $argu | grep -E "^-") ]] && set -- "$@" "${argu//-/}" || echo "no - symbol. not touching $argu" &>/dev/null ;; esac done #echo -e "/n final option conversions = $@/n" # remove options from positional parameters for getopts parsing shift $(expr $OPTIND - 1) declare -i runscript=0 # only p requires an argument hence the p: while getopts "sSp:" param; do [[ "$param" == "p" ]] && [[ $(echo $OPTARG | grep -E "^-") ]] && funcUsage "order" #echo $param #echo "OPTIND=$OPTIND" case $param in s) OPTARG=${OPTARG/ /} getoptsRan=1 echo "$param was passed and this is it''s arg $OPTARG" arg0=start ;; p) OPTARG=${OPTARG/ /} getoptsRan=1 echo "$param was passed and this is it''s arg $OPTARG" [[ "$OPTARG" == "all" ]] && echo -e "argument /"$OPTARG/" accepted. continuing." && (( runscript += 1 )) || usage="open" [[ $( echo $pbString | grep -w "$OPTARG" ) ]] && echo -e "pb $OPTARG was validated. continuing./n" && (( runscript += 1 )) || usage="personal" [[ "$runscript" -lt "1" ]] && funcUsage "$usage" "$OPTARG" arg0=start ;; S) OPTARG=${OPTARG/ /} getoptsRan=1 echo "$param was passed and this is it''s arg $OPTARG" arg0=stop ;; *) getoptsRan=1 funcUsage echo -e "Invalid argument/n" ;; esac done funcBuildExcludes "$@" shift $((OPTIND-1))


No puede usar el Getopts Bash builtin para opciones largas, al menos no sin tener que crear sus propias funciones de análisis. Debería echar un vistazo al binario / usr / bin / getopt (proporcionado en mi sistema por el paquete util-linux ; su millaje puede variar).

Vea getopt (1) para opciones de invocación específicas.


getopts es usado por los procedimientos de shell para analizar parámetros posicionales de 1 carácter solamente (no hay opciones largas de estilo GNU (--myoption) o opciones largas de estilo XF86 (-myoption))


getopts solo puede analizar opciones cortas.

La mayoría de los sistemas también tienen un comando externo getopt , pero getopt no es estándar, y generalmente está roto por diseño ya que no puede manejar todos los argumentos de forma segura (argumentos con espacios en blanco y vacíos), solo GNU getopt puede manejarlos de manera segura, pero solo si Lo usas de una manera específica de GNU.

La opción más fácil es usar ninguno de los dos, simplemente iterar los argumentos del script con un ciclo while y hacer el análisis usted mismo.

Vea http://mywiki.wooledge.org/BashFAQ/035 para un ejemplo.