Eu tenho um script bash e só quero oferecer suporte a opções longas ("--option"). Uma --option pode opcionalmente ter um ou mais argumentos. Todas as palavras (qualquer coisa delimitada por espaço em branco) até, mas não incluindo, o primeiro '--' OU o final da string da linha de comando são consideradas "--option-arguments". Um espaço à direita no resultado é aceitável. O desempenho máximo é desejado, pois esta função é chamada por outras funções para cada opção possível. Assim, tentando evitar loops bash e comandos externos.
Lutei por muitas horas com o problema da "primeira ocorrência" até encontraresta respostaisso me lembrou que o POSIX (e, portanto, o bash) não oferece suporte a operadores regex não gananciosos/preguiçosos.
O que fazer?
Responder1
Você não pode analisar opções com expressões regulares da maneira que deseja porque as opções não são passadas em uma string, mas em umlistade cordas. myscript --option foo bar -- qux
tem myscript
, --option
, foo
, bar
e --
como qux
argumentos separados, nenhum deles contendo espaços em branco.
Um loop é o caminho a percorrer no bash.
case "$1" in
--option1)
shift
while [[ $# -ne 0 && "$1" != "--" ]]; do
option1_args+=("$1")
shift
done
(($# == 0)) || shift
done
Se o desempenho é um problema tão grande, você não deveria usar o bash. Em vez disso, experimente o ksh - é gratuito, está disponível em praticamente todos os lugares, mesmo que não esteja instalado por padrão, e geralmente é significativamente mais rápido que o bash. Se ainda for muito lento, você precisará de uma linguagem de programação mais sofisticada, como Perl, Python ou Ruby.
Responder2
Encontrei esta solução bastante simples ...
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 um script ou chamada de função com opções seguidas de outras opções, como...
otherfunction --option1 arg1 arg2 --option2 -- file1 /home/me/file2
Para cada opção aceita por otherfunction(), optionArg() seria chamada como...
_optarg1="$(optionArg --option1 "$@")"
_optarg2="$(optionArg --option2 "$@")"
_optarg3="$(optionArg -- "$@")"
Os resultados seriam...
_optarg1="arg1 arg2 "
_optarg2=""
_optarg3="file1 /home/me/file2"