Comparando duas strings no Bash

22

Eu tenho o seguinte ifbloco no meu script bash:

if [ ${PACKAGENAME} -eq kakadu-v6_4-00902C ]; then
  echo "successfully entered if block!!"
fi

A execução do script não está entrando no meu ifbloco, embora $PACKAGENAMEseja igual a kakadu-v6_4-00902C. O que estou fazendo errado?

DemiSheep
fonte
9
-eqé verdadeiro para números inteiros, você quer teste para uma string ou expressão regular ( ==ou =~): mywiki.wooledge.org/BashGuide/TestsAndConditionals
jasonwryan
Obrigado jasonwryan, vou dar uma olhada neste recurso!
DemiSheep 17/07/2014

Respostas:

31

-eq é um operador aritmético, que compara dois números.

Use =(portátil / padrão sh) =~ou , em ==vez disso.

Também use aspas, porque se ${PACKAGENAME}contiver um caractere de espaço em branco ou curinga, ele será dividido em vários argumentos, o que faz com que [veja mais argumentos que o desejado. Veja aqui uma lista de armadilhas comuns do bash.

if [ "${PACKAGENAME}" = 'kakadu-v6_4-00902C' ]; then
    echo "successfully entered if block!!"
fi

Veja man bash, pesquise ( /) por CONDITIONAL EXPRESSIONS.

polym
fonte
1
Ah! Obrigado! Funcionou! Eu sou obviamente um novato nisso. Sou grato por sua ajuda!
DemiSheep 17/07/2014
2
Você já viu tldp.org/LDP/Bash-Beginners-Guide/html ? É um guia do bash muito bom e ajudará você com exemplos e exames :).
Polym
1
Obrigado polym, vou dar uma olhada, obrigado pelo recurso! Vou abrir essa guia ao lado do meu guia VI. :)
DemiSheep
4
Entre colchetes duplos, nenhuma divisão de palavras é feita, o que também [[ $PACKAGENAME == "kakadu..." ]]é aceitável.
Glenn Jackman
4
@glennjackman Cuidado, porém, que mesmo dentro de colchetes duplos, você precisa de aspas em torno expansões variáveis no lado direito de =, ==e !=, por esse lado é um padrão, não uma string. Por exemplo, foo='*'; [[ whatever = $foo ]]é verdade.
Gilles 'SO- stop be evil'
6

Substitua -eqpor == para que o seu bloco if seja o seguinte: -

if [ ${PACKAGENAME} == kakadu-v6_4-00902C ]; then

        echo "successfully entered if block!!"

fi
iniciante
fonte
5
Não se esqueça de citar! Dê uma olhada aqui, por que: mywiki.wooledge.org/BashPitfalls#A.5B_.24foo_.3D_.22bar.22_.5D
polímer
@ polym hey obrigado, mas eu apenas dei a versão minimalista que estava funcionando;): D.
Iniciante 18/07
4

Outra maneira é negá-los:

: ${PACKAGENAME:?'$PACKAGENAME variable is empty!'} #emits error and exits
[ -z "${PACKAGENAME#kakadu-v6_4-00902C}" ] || { #if var - str not empty do block
    echo '$PACKAGENAME is not kakadu-v6_4-00902C' 
    exit 1
} >&2

O bloco acima primeiro testa se "$PACKAGENAME"tem algum valor e, se não, sai com erro e ecoa ?'this'}para stderr. Se o shell pai ainda existir, o teste foi aprovado e o próximo teste se a remoção da string 'kakadu ...' da variável resultar em uma -zstring vazia. Caso contrário, emite novamente um erro e sai do shell. Se o seu shell ainda existir neste momento, qualquer coisa após a execução do bloco, caso contrário, não existe.

Provavelmente, esse tipo de coisa é melhor implementado em uma função. Gostar:

argeq() ( i= : ${2?^MERR: not enough parameters!} #$#>=2 || quit w/ err ^M == \r
    z() { return $((${#1}>0)) ; } #return 1 if ${#1}>0 else 0
    until z "${2+?}" $((i=i+1)) #until $2 is not set...
    do  ! z "$1" && z "${1#"$2"}" || #$1 != '' && $1 - $2 == '' or...
        exit $((i${1:++1})) #exit $? == failed arg count
    shift ; done #shift away one param ; continue loop
)

Com essa função, você pode fornecer quantos argumentos o seu sistema permitir. Se você fornecer menos de 2, ele retornará 1 e emitirá uma mensagem para stderr. Se você fornecer 2 ou mais argumentos, ele tratará todos como seqüências de caracteres e retornará 0 se todos forem idênticos e não nulos; caso contrário, retornará o número do argumento que primeiro falha na verificação.

No seu caso, pode ser usado como:

{   
    PACKAGENAME='kakadu-v6_4-00902C'
    argeq "$PACKAGENAME" kakadu-v6_4-00902C &&
        echo "kakadu-v6_4-00902C == $PACKAGENAME" ||
        echo failure
    ! argeq "${PACKAGENAME#*-}" kakadu-v6_4-00902C &&
        echo "kakadu-v6_4-00902C != ${PACKAGENAME#*-}" ||
        echo failure
}

###OUTPUT###
kakadu-v6_4-00902C == kakadu-v6_4-00902C
kakadu-v6_4-00902C != v6_4-00902C

Para demonstrar ainda mais, escreverei outra função:

aeqecho() { i=$((i+1)) #inc for line#
    argeq "$@" && echo "$i : yay" || #allswell or
    ! e=$? ${2+:} return || #save $?; ! exclusive || to drop ERRs
    echo "$i : shite - arg$e failed" #report failure
}

DEMO:

{  i= s=string
   aeqecho $s #1
   aeqecho $s $s #2
   aeqecho "$s $s" #3
   aeqecho "$s $s" "${s} string" #4
   aeqecho "${s}1" $s string #5
   aeqecho "" "" "" #6
   aeqecho "" "$s" $s #7
   aeqecho 1 "${s#$s}1" $((2-1)) #8                     
   aeqecho $s $s $s $s $s $s $s $s $s $s $s $s stng #9  
   aeqecho $s $s $s $s $s $s $s $s $s $s $s $s string #10
}  

SAÍDA:

ERR: not enough parameters!
2 : yay
ERR: not enough parameters!
4 : yay
5 : shite - arg2 failed
6 : shite - arg1 failed
7 : shite - arg1 failed
8 : yay
9 : shite - arg13 failed
10 : yay
mikeserv
fonte