Por que meu elif está sendo tratado como uma instrução else em meu script bash?

2

Estou criando um script bash que usa wget para obter informações de um servidor usando uma API REST. Estou usando getopts para analisar as opções fornecidas ao script e, em seguida, usando uma instrução if para redirecionar o script corretamente com base nas opções fornecidas. O if vai para o corpo principal do script (ou seja, a chamada wget), o elif imprime o menu de ajuda e o outro imprime uma mensagem de erro. No entanto, meu elif parece estar agindo como uma declaração mais. Quando eu corro:

>./jira -h

Recebo a resposta adequada, por exemplo, o menu de ajuda:

----------jira options----------
Required:
-d [data/issueID]
-u [username] -> [username] is your JIRA username
-p [password] -> [password] is your JIRA password

Optional:
-q -> quiet, i.e. no output to console
-h -> help menu

No entanto, quando executo algo que deveria me fornecer a mensagem de erro, recebo o menu de ajuda:

>./jira -u jsimmons

----------jira options----------
Required:
-d [data/issueID]
-u [username] -> [username] is your JIRA username
-p [password] -> [password] is your JIRA password

Optional:
-q -> quiet, i.e. no output to console
-h -> help menu 

Meu script está abaixo:

#!/bin/bash

#using getopts to parse options
while getopts ":hqd:u:p:" opt; do
        case $opt in
                h)
                        help="true"
                        ;;      
                q)
                        quiet="true"
                        ;;      
                d)
                        data=$OPTARG
                        ;;
                u)
                        username=$OPTARG
                        ;;
                p)
                        password=$OPTARG
                        ;;
                \?)
                        echo "Invalid option: -$OPTARG" >&2
                        ;;
                :)
                        echo "Option -$OPTARG requires an argument." >&2
                        ;;
        esac
done

#check if required options have been set
if [[ -n $data && -n $username && -n $password ]]; then 

        wget -q \
            --http-user=$username \
            --http-passwd=$password \
            --header="Content-Type: application/json" [URI]


        #placing issue info into variable

        response=$(< $data) 


        #using heredoc to run python script
        #python script uses regular expressions to find the value of the field 
        #customfield_10701 ie the branch version 

        output=$(python - <<EOF
import re

matchObj = re.search(
     r'(?<=customfield_10701":").*(?=","customfield_10702)',
     '$response',
     re.I
)
if(matchObj):
        print(matchObj.group())

EOF
)


        #writes branch version in .txt file

        echo $output>branchversion.txt 


        #prints the branch version if the quiet option hasn't been set 
        if [ -z $quiet ]; then
                echo "-------------------------------------------" 
                echo ""
                echo "The branch version for issue $data is:"
                cat branchversion.txt
                echo ""
        fi

        #removes file that wget creates containing all data members for the issue

        rm $data
elif [ -n $help ]; then 
        #if help option has been set    
        echo "" 
        echo "----------jira options----------"
        echo "Required:"
        echo "-d [data/issueID]"
        echo "-u [username] -> [username] is your JIRA username"
        echo "-p [password] -> [password] is your JIRA password"
        echo ""
        echo "Optional:"
        echo "-q -> quiet, i.e. no output to console"
        echo "-h -> help menu"
        echo ""
        #http GET data members for issue
else
        #if not all required options or help have been set      
        echo "Error: Missing argument(s)"
        echo "Usage: ./jira [option(s)] -d [data] -u [username] -p [password]"
        echo "" 
        echo "Try: ./jira -h for more options"
fi
    
por Void 09.06.2016 / 18:06

3 respostas

2

a opção -n verifica se uma string tem comprimento diferente de zero.

if [ ... ]; then #posix compliant condition tests

if [[ ... ]]; then #extended condition tests

Parece que os testes de condições estendidas funcionam de forma diferente dos posix.

> if [ -n $unsetVar ];then echo yes ; fi
yes
>

> if [ -n "$unsetVar" ];then echo yes ; fi
>

> if [[ -n $unsetVar ]];then echo yes ; fi
>

use as condições estendidas para [[ ... ]] ou envolva sua variável entre aspas. Atualmente, sua instrução elif é sempre verdadeira.

    
por 09.06.2016 / 18:19
2

O problema fundamental é que você omitiu aspas duplas em torno de uma substituição de variável . Quando você escreve $help , na maioria dos contextos, isso não significa “pegar o valor de help ”, isso significa “pegar o valor de help , interpretá-lo como uma lista separada por espaço em branco de padrões de caractere curinga e substitua cada padrão pela lista de nomes de arquivos correspondentes se pelo menos um nome de arquivo corresponder ”.

Quando help está vazio, [ -n $help ] expande para a lista de três palavras [ , -n , ] , pois o resultado de split + glob em uma sequência vazia é uma lista vazia de palavras. Quando há uma única palavra entre parênteses, a condição é verdadeira a menos que a palavra esteja vazia. -n não está vazio, então a condição é verdadeira.

A correção é escrever [ -n "$help" ] : quando help está vazio, isso é expandido para a lista de quatro palavras [ , -n , palavra vazia, ] . Isso aplica o operador -n à palavra vazia e a condição é falsa.

Uma solução alternativa é usar [[ -n $help ]] . Os colchetes duplos são sintaxe especial, com diferentes regras de análise (enquanto colchetes são um comando comum com um nome engraçado). Dentro de colchetes duplos, você pode deixar aspas duplas em torno das substituições de variáveis na maioria dos contextos, com exceção do lado direito de = , == , != e =~ . Você pode escrever [[ -n "$help" ]] se quiser, então você não precisa se lembrar das exceções onde deixar as aspas duplas é permitido: apenas lembre-se de sempre colocar aspas duplas em torno de substituições de variáveis (e similarmente em torno de substituições de comandos: "$(foo)" ) .

    
por 10.06.2016 / 02:37
1
  1. você nem precisa de um if / elif aqui. Em vez de -h setting help=true , crie uma função usage() que imprima a ajuda de uso e saia do script, a opção -h poderá, então, chamar essa função.

  2. Por que você está usando código Python incorporado para fazer um trabalho que poderia ser feito mais facilmente com grep ou sed ou awk ? ou jq

  3. seu código não funcionará de qualquer maneira. Você parece ter ficado confuso sobre o que $data contém. De acordo com a ajuda e a instrução case getopts, $data contém o data/issueID .... mas parece que você está assumindo que ele contém o conteúdo de um URL buscado com wget .

    Na verdade, parece que você nem usa esse -d data / issueID ... talvez você deva incluí-lo em uma string de consulta na solicitação wget ?

    ou -d supostamente tem um nome de arquivo como argumento? Na mensagem de ajuda, não parece provável.

De qualquer forma, aqui está uma versão que corrige a maioria dos problemas (e, IMO, melhora muito a legibilidade do script):

#!/bin/bash

URI='...whatever...'

usage() {
# print optional error message and help message and exit.

[ -z "$*" ] || printf "%s\n\n" "$*"
# or, if you don't want help printed with every error message:
# [ -z "$*" ] || printf "%s\n\nUse -h option for help.\n" "$*" && exit 1

cat >&2 <<__EOF__
----------jira options----------
Required:
  -d [data/issueID]
  -u [username] -> [username] is your JIRA username
  -p [password] -> [password] is your JIRA password

Optional:
  -q -> quiet, i.e. no output to console
  -h -> help menu
__EOF__

exit 1
}

quiet=''

#using getopts to parse options
while getopts ":hqd:u:p:" opt; do
  case $opt in
     h) usage ;; 
     q) quiet='true' ;;     
     d) data="$OPTARG" ;;
     u) username="$OPTARG" ;;
     p) password="$OPTARG" ;;
    \?) usage "Invalid option: -$OPTARG" ;;
     :) usage "Option -$OPTARG requires an argument." ;;
  esac
done

# check for required options

[ -z "$data" ]     && usage '-d is required'
[ -z "$username" ] && usage '-u is required'
[ -z "$password" ] && usage '-p is required'

# your embedded python overkill could easily be done with 'sed'
# or 'awk'.   or maybe 'jq' as the wget output is json.
# but without a sample of the input I can't provide a guaranteed
# working example.  The awk script below is a first attempt at
# extracting the value of 'customfield_10701'

wget -q --http-user="$username" \
        --http-passwd="$password" \
        --header='Content-Type: application/json' \
        -O -
        "$URI" |
  awk -F': ' '/"customfield_10701"/ {
                gsub(/[",]/,"",$2);
                print $2
              }' > branchversion.txt

# alternatively, if you have 'jq' installed, try piping wget's
# output through something like 'jq -r .customfield_10701' instead of awk.

#prints the branch version if the quiet option hasn't been set
if [ -z "$quiet" ]; then
  echo "-------------------------------------------"
  echo ""
  echo "The branch version for issue $data is:"
  cat branchversion.txt
  echo ""
fi
    
por 10.06.2016 / 03:47