Como eu uso valores inseridos usando getopts?

2

Eu tenho este código bash combinado com getopts e se eu entendi getopts corretamente OPTIND contém o índice da próxima opção de linha de comando e todas as opções de linha de comando fornecidas ao shell script são apresentadas nas variáveis $ 1, $ 2, $ 3 etc. Corrigir-me se eu estiver errado mas basicamente o mesmo conceito que variáveis locais nas funções .

Então, de acordo com isso, porque as opções [-a somevalue ] ou [-b somevalue ] não me dão nenhum resultado. O que estou fazendo de errado?

OPT_A=A
OPT_B=B

while getopts :a:b FLAG; do
 case $FLAG in
    a) 
      OPT_A=$OPTARG
      ;;
    b) 
     OPT_B=$OPTARG
      ;;
  esac
done

shift $((OPTIND-1))

    while [ $# -ne 0 ]; do

if [[ -z $OPT_A ]]; then
    if [ 'echo $1 | grep -o '\.' | wc -l' -ne 3 ]; then
        echo "Parameter '$1' does not look like an IP Address (does not contain 3 dots).";
            exit 1;
        elif [ 'echo $1 | tr '.' ' ' | wc -w' -ne 4 ]; then
            echo "Parameter '$1' does not look like an IP Address (does not contain 4 octets).";
        exit 1;
            else
        for OCTET in 'echo $1 | tr '.' ' ''; do
                if ! [[ $OCTET =~ ^[0-9]+$ ]]; then
                        echo "Parameter '$1' does not look like in IP Address (octet '$OCTET' is not numeric).";
                        exit 1;
                elif [[ $OCTET -lt 0 || $OCTET -gt 255 ]]; then
                        echo "Parameter '$1' does not look like in IP Address (octet '$OCTET' in not in range 0-255).";
                        exit 1;
                fi
        done
    fi
fi


if [[ -z $OPT_B ]]; then
        if [[ "$2" =~ ^[0-9]+$ ]] && [ "$2" -ge 1 -a "$2" -le 10000 ]; then 
            echo "chosen variable: $2";
            exit 1;
            else echo "variable $2 is not in range '1 - 10000'";
            exit 1;
        fi
    fi

    done
    exit 0
    
por ticket 27.02.2015 / 15:52

3 respostas

2

É porque toda a sua lógica depende do $OPT_[AB] sendo nulo. Mas, mesmo que você não passe um parâmetro -[ab] $OPTARG , ainda estará definindo-os na parte superior do script com OPT_[AB]=[AB] . Então suas cadeias lógicas nunca passam da raiz ...

if [[ -z $OPT_A ]]; then...

... declaração.

Bem ... não tudo da sua lógica depende disso. Você também está fazendo:

shift $((OPTIND-1))

    while [ $# -ne 0 ]...

Então, se você passou script -a arg , então getopts definiria $OPT_A para arg e $OPTIND chegaria a 3. Então você shift 2 (todos os seus posicionais) então falhar imediatamente o teste em while . Portanto, seu case definiria $OPT_A e a próxima coisa que acontece é exit 0 . Então, eu acho que você nunca teria que procurar um $OPT_A vazio de qualquer forma.

E mesmo isso seria ok, já que a maior parte de sua lógica é projetada para testar falhas - mas seu script somente exit s. Você provavelmente faz o $OPT_A var, mas não faz nada com ele. Você não pode usar esse valor depois do script exit s - não sem algum IPC predefinido, mas não há nada disso aqui. O script é chamado em um subshell e os valores que ele configura são perdidos quando ele retorna ao shell pai.

O que é mais, o optstring :a:b não permite um $OPTARG a -b . Um cólon principal na optstring significa operação silenciosa - ele não grava em stderr se houver um problema com as opções ou seus argumentos. Mas um cólon arrastando uma opção é o que significa que a opção deve esperar um argumento. Como:

while getopts :a:b: FLAG

... isso indicaria duas opções que esperam argumentos. Pode ser complicado, porque se você indicar que ele deveria receber um argumento, então se getopts o encontrar sem um, ele o sinaliza como um erro:

sh -c 'getopts :a:b: opt -a; echo "$opt $OPTARG"'

... que imprime ...

: a

Nesse caso, a opção acaba em $OPTARG e a : acaba em $opt . É mais claro se estamos menos : quietos sobre isso:

sh -c 'getopts a:b: opt -a; echo "$opt $OPTARG"'
No arg for -a option

Então, você precisa verificar : colon e ? - que é outro tipo de erro e que é reencaminhado convencionalmente para imprimir algum tipo de coisa curta em --help .

Pessoalmente, eu me certificaria de que $OPT_[AB] estavam vazios para começar, faça alguma lógica para configurá-los corretamente e, quando terminar o loop de teste, faça o último teste para um valor nulo. Se eles não têm qualquer valor, então deve ser por algum motivo que não tenho tratado, e é um erro, independentemente. Aqui está um começo de como eu iria trabalhar nesse loop de teste ...

param_err(){
    set '' "$@"
    : "${1:?Parameter '$OPTARG' does not look like an IP Address $2}"
}

test_oct(){ 
    oIFS=$IFS; unset "${IFS+o}oIFS"; IFS=.
    for oct in $1; do  [ $oct -lt 256 ] || 
        param_err "('$oct' too large)"
    done; unset IFS oct
    : "${oIFS+${IFS=$oIFS}}"
}

a_param()
    case ${1##*.*.*.*.*} in (a) OPT_A=A;;  #some default - no arg provided                                            
          (.*|*..*|*.) param_err '(empty octet)';;
          (*[!.0-9]*)  param_err '(octet is not positive integer)';;
          (*.*.*.*)    test_oct  "$1"; OPT_A=$1;;
          (*?*)        param_err '(too few octets)';;
          (*)          param_err ${1:+"(too many octets)"} '(null param)';;
    esac

unset OPT_A OPT_B
while getopts :a:b:c:d: opt
do    case ${opt#:}$OPTARG in
      a*)   a_param "$OPTARG";;
      b*)   b_param "$OPTARG";; #tests as needed similar to a_param()
      ?*)   help;;              #param_err should call this too, but it just exits
      esac
done                
    
por 27.02.2015 / 17:10
0

Você não tem uma linha no topo, então o shell que você está usando ( sh , dash ) provavelmente não suporta [[ . Você deve iniciar o script com:

#!/bin/bash

ou qualquer outro local em que bash esteja, no caso improvável de não ser o caminho para atacar seu sistema ( type bash ).

    
por 27.02.2015 / 16:30
0

Tente mudar isso: enquanto getopts: a: b FLAG; fazer

Para isso: enquanto getopts: a: b: FLAG; fazer

    
por 27.02.2015 / 19:11