Cómo lidiar con el fin de las opciones - en getopts

9

Utilizo getopts para analizar argumentos en scripts de bash como

while getopts ":hd:" opt; do
  case $opt in
    d ) echo "directory = $OPTARG"; mydir="$OPTARG"; shift $((OPTIND-1)); OPTIND=1 ;;
    h ) helptext
      graceful_exit ;;
    * ) usage
      clean_up
      exit 1
  esac
done

exeparams="$*"

exeparamsmantendrá las opciones / argumentos no analizados. Dado que quiero usar exeparams para mantener las opciones para que un comando se ejecute dentro del script (que puede superponerse con las propias opciones de scripts), quiero usar - para finalizar las opciones pasadas al script. Si paso, por ejemplo

myscript -d myscriptparam -- -d internalparam

exeparams sostendrá

-- -d internalparam

Ahora quiero eliminar la guía --para pasar estos argumentos al comando interno. ¿Hay una manera elegante de hacer esto o puedo obtener una cadena que contenga solo el resto sin --getopts?

Highsciguy
fuente
Poner shift; OPTIND=1dentro del getoptsciclo probablemente no sea la mejor manera de hacerlo. Solo funciona en su caso porque solo tiene 2 opciones y en todas las demás simplemente sale del script. De lo contrario, necesitaría shift; OPTIND=1en cada opción, lo que significa código duplicado (mala práctica). Simplemente haga una shift $((OPTIND - 1))inmediatamente después del final del ciclo: esta es la forma más convencional y probablemente también la más eficiente.
jw013

Respuestas:

7

Qué tal si:

# ... getopts processing ...

[[ $1 = "--" ]] && shift
exeparams=("$@")

Tenga en cuenta que debe usar una matriz para contener los parámetros. Eso manejará adecuadamente cualquier argumento que contenga espacios en blanco. Desreferenciar la matriz con"${exeparams[@]}"

Glenn Jackman
fuente
1
Esto supone que no hay argumentos entre el final de las opciones y --, es decir script foo -- bar, pasaría foo -- baral programa externo. Mi respuesta no hace esa suposición, ya que no se mencionó explícitamente en la pregunta.
jw013
Excepto donde el OP dice "Ahora quiero eliminar el líder -"
Glenn Jackman
Eso fue por el ejemplo -- -d internalparams. En cualquier caso, mi respuesta es lo suficientemente general como para manejar cualquier caso.
jw013
14

Utiliza el incorporado shift. Primero, haz lo normal getoptspara tu guión. Una vez que se completa ese ciclo,

shift "$((OPTIND - 1))"

cambiará todas las opciones ya procesadas.

A partir de ahí, tendrá que terminar de procesar los argumentos que no son de opción, si los hay, hasta la primera parte del script (antes de --). Una vez que encuentre el --, muévalo hasta que solo quede la última parte (la -d internalparamparte que viene después --). Una forma de hacer esto (usando la bashsintaxis):

while [[ $# -gt 0 ]]; do
    # process next argument
    case $1 in
    foo) # process foo
    ;;
    --) shift; break;; # found '--', discard it and exit loop
    *) # handle unrecognized argument
    ;;
    esac
    # not '--', so discard the argument and continue
    shift
done

Finalmente, solo queda el segundo conjunto de opciones / argumentos, que puede transmitir. No NO utilizar $*para pasar el resto de parámetros a otro comando. Use en su "$@"lugar, lo que conserva la división original de la palabra.

external_command "$@"
jw013
fuente
¡Si gracias! Pero, ¿cómo encuentro exactamente --?
highsciguy