Como as opções podem ser analisadas em um script Bash, deixando as opções não reconhecidas após o “-”?

1

Estou procurando uma maneira de fazer a análise de opções em um script Bash (permitindo tanto argumentos curtos quanto longos como getopt ) que interrompe a análise no primeiro argumento não reconhecido, coloca um - antes do primeiro argumento não reconhecido, e copia os argumentos restantes para a string de saída.

Por exemplo, aqui está o comportamento que eu quero:

% OPTIONS=("-u" "name1" "--username=name2" "-x" "a" -u "b" "c")
% getopt -o u: -l username: -n programname -- "${OPTIONS[@]}"
-u 'name1' --username 'name2' -- -x 'a' -u 'b' 'c'
%

O utilitário getopt não funciona dessa maneira e, em vez disso, emite o seguinte:

programname: invalid option -- 'x'
-u 'name1' --username 'name2' -u 'b' -- 'a' 'c'

Note que não quero que os argumentos que seguem uma opção não reconhecida sejam reordenados como se fossem reconhecidos, como demonstrado acima com a segunda opção -u . Espero que alguém tenha uma solução que forneça os resultados que demonstro no primeiro bloco de código acima. Alguma idéia?

Ambiente: bash 4.2.46 (1), CentOS 7.2 @ 3.10.0-327.36.1.el7.x86_64.

Requisitos: CentOS 7.2 Mínimo, sem software adicional para ser instalado com todo o código escrito em um script Bash. As opções passadas para o analisador de opções não precisam incluir - nelas (ou seja, o término da análise deve ser automático).

    
por Steve Amerige 12.10.2016 / 11:17

2 respostas

2

A solução para esse problema requer algo diferente de getopt porque getopt reorganiza as opções que ele encontra que correspondem à especificação da opção e termina em opções não reconhecidas. O getopts embutido do Bash vem para o resgate, mas precisa ser capaz de lidar com opções longas. Em uma postagem de Arvid Requate e TomRoche , há um "truque" que permite que o getopts lide com opções longas: use - como uma especificação de opção e use dois pontos principais no especificação de opções para silenciar o relatório de erros. Sua solução, no entanto, exigiria que o código fosse duplicado para lidar com opções curtas e longas.

Aqui está uma solução que testei e atende a todos os meus requisitos, além de não duplicar o processamento de opções curtas e longas. Para maior clareza e integridade, mudei username para set e adicionei toggle para demonstrar opções que não aceitam valores.

parse.sh

#!/bin/bash

Options=("$@")
while getopts ":s:-:" OptChar "${Options[@]}"; do
   case "$OptChar" in
    -)   case "$OPTARG" in
         set|set=*)
            if [[ $OPTARG =~ ^set= ]] ; then
               Value="${Options[$OPTIND-2]#*=}"
            else
               Value="${Options[$OPTIND-1]}"
               ((OPTIND++))
            fi
            echo "Parsed: --$OPTARG, value: '$Value'"
            ;;

         toggle)
            echo "Parsed: --$OPTARG";;
         *) ((OPTIND--)); break;;
         esac
         ;;

   # Redirect short arguments to long arguments
   s)    ((OPTIND-=2)); Options[OPTIND-1]="--set";;
   t)    ((OPTIND--)); Options[OPTIND-1]="--toggle";;

   *)    ((OPTIND--)); break;;
   esac
done
Options=( "${Options[@]:$OPTIND-1}" )

echo "REMAINING Options: ${Options[@]}"

e aqui está o meu código de teste:

% ./parse.sh --set=a  -s b --set= --set c --unknown -s d --set e
Parsed: --set=a, value: 'a'
Parsed: --set, value: 'b'
Parsed: --set=, value: ''
Parsed: --set, value: 'c'
REMAINING Options: --unknown -s d --set e
%
% ./parse.sh -s a -x -s b
Parsed: --set, value: 'a'
REMAINING Options: -x -s b
%
    
por 12.10.2016 / 14:13
0

Isso pode funcionar se você não usar opções curtas combinadas, como "-ax":

OPTIONS=("-u" "name1" "--username=name2" "-x" "a" -u "b" "c")

for i in 'seq ${#OPTIONS[@]} -1 0'; do
  OFIRST=("${OPTIONS[@]:0:$i}")
  getopt -o u: -l username: -n programname -- "${OFIRST[@]}" &>/dev/null && break
done

NEWOPT=("${OPTIONS[@]:0:$i}" "--"  "${OPTIONS[@]:$i}")

getopt -o u: -l username: -n programname -- "${NEWOPT[@]}"

Tenho certeza de que há problemas com essa solução. Provavelmente é melhor você tentar adicionar esse recurso ao código-fonte getopt.c do util-linux.

    
por 12.10.2016 / 13:11