Tengo un script bash y solo quiero admitir opciones largas ("--option"). Una opción --option puede tener opcionalmente uno o más argumentos. Todas las palabras (cualquier cosa delimitada por espacios en blanco) hasta el primer '--' O el final de la cadena de línea de comando, pero sin incluirlo, se consideran "--argumentos de opción". Un espacio final en el resultado está bien. Se desea el máximo rendimiento ya que esta función es llamada por otras funciones para cada opción posible. Por lo tanto, intentamos evitar bucles de bash y comandos externos.
Luché durante muchas horas con el problema de la "primera aparición" hasta que encontréesta respuestaeso me recordó que POSIX (y por lo tanto bash) no admite operadores de expresiones regulares no codiciosos/perezosos.
¿Qué hacer?
Respuesta1
No puede analizar opciones con expresiones regulares de la manera que parece querer porque las opciones no se pasan en una cadena, sino en unlistade cuerdas. myscript --option foo bar -- qux
tiene myscript
, --option
, foo
, bar
y --
como qux
argumentos separados, ninguno de ellos contiene espacios en blanco.
Un bucle es el camino a seguir en bash.
case "$1" in
--option1)
shift
while [[ $# -ne 0 && "$1" != "--" ]]; do
option1_args+=("$1")
shift
done
(($# == 0)) || shift
done
Si el rendimiento es un gran problema, no deberías usar bash. Pruebe ksh en su lugar: es gratis, está disponible prácticamente en todas partes incluso si no está instalado de forma predeterminada y, a menudo, es significativamente más rápido que bash. Si todavía es demasiado lento, necesita un lenguaje de programación más sofisticado como Perl, Python o Ruby.
Respuesta2
Encontré esta solución bastante simple...
function optionArg () {
local _find="$1"; shift 1
local _optarg=""
local _reBeg=""
#
_reBeg="${_find}"'[= ]+(.*?)( --)?'
### no regex nongreedy operator support in POSIX
### will have to just truncate after first match
#
if [[ "$*" =~ $_reBeg ]]
then
_optarg="${BASH_REMATCH[1]}"
### all arguments following --option[= ]
#
_optarg="${_optarg%%--*}"
### limit to just arguments up to next --option (no lazy support in POSIX)
#
return 0
else
return 1
fi
Dado un script o llamada de función con opciones seguidas de otras opciones como...
otherfunction --option1 arg1 arg2 --option2 -- file1 /home/me/file2
Para cada opción aceptada por otherfunction(), optionArg() se llamaría así...
_optarg1="$(optionArg --option1 "$@")"
_optarg2="$(optionArg --option2 "$@")"
_optarg3="$(optionArg -- "$@")"
Los resultados serían...
_optarg1="arg1 arg2 "
_optarg2=""
_optarg3="file1 /home/me/file2"