Como comparar seqüências de caracteres no Bash


Respostas:


1376

Usando variáveis ​​em instruções if

if [ "$x" = "valid" ]; then
  echo "x has the value 'valid'"
fi

Se você quiser fazer algo quando não corresponder, substitua =por !=. Você pode ler mais sobre operações de string e operações aritméticas na respectiva documentação.

Por que usamos aspas $x?

Você quer as aspas $x, porque se estiver vazio, seu script Bash encontrará um erro de sintaxe, como mostrado abaixo:

if [ = "valid" ]; then

Uso não padrão do ==operador

Observe que o Bash permite ==ser usado para igualdade com [, mas isso não é padrão .

Use o primeiro caso em que as aspas $xsão opcionais:

if [[ "$x" == "valid" ]]; then

ou use o segundo caso:

if [ "$x" = "valid" ]; then

12
Como isso se relaciona com a resposta aceita dada no Erro inesperado do operador ? Eu recebi o mesmo erro ao usar [ "$1" == "on" ]. Alterar isso para ["$ 1" = "on"] resolveu o problema.
Piotr Dobrogost

78
Os espaços são necessários.
TAAPSogeking

6
@ JohnFeminella Ao escrever em um script bash, ele deve ter um único =e não dois.
User13107

73
pode valer a pena notar que você não pode usar [ $x -eq "valid" ]. -eqé o operador de comparação para números inteiros, não seqüências de caracteres.
craq

2
@ Alex, em que casos (se houver) eu preciso usar o padrão ["x$yes" == "xyes"], que é o prefixo da variável e da string literal com um x? Isso é uma relíquia dos velhos tempos ou é realmente necessário em algumas situações?
lanoxx

142

Ou, se você não precisar de outra cláusula:

[ "$x" == "valid" ] && echo "x has the value 'valid'"

71
E se você precisar de uma cláusula else e quiser criar uma linha louca: ["$ x" == "valid"] && echo "valid" || eco "inválido"
Matt White

11
@ MattWhite: isso geralmente é uma má idéia, pois echopode falhar.
gniourf_gniourf

1
mesmo tho armadilhas que podem aparecer, formas bonitas e elegantes de ambos Marko && MattWhite
Deko

3
@gniourf_gniourf, não há problema, use [ "$X" == "valid" ] || ( echo invalid && false ) && echo "valid" .
12431234123412341234123

4
@ 12431234123412341234123 { echo invalid && false; }é mais eficiente do que ( echo invalid && false ), pois evita pagar por um subshell desnecessário.
22818 Charles Duffy

84
a="abc"
b="def"

# Equality Comparison
if [ "$a" == "$b" ]; then
    echo "Strings match"
else
    echo "Strings don't match"
fi

# Lexicographic (greater than, less than) comparison.
if [ "$a" \< "$b" ]; then
    echo "$a is lexicographically smaller then $b"
elif [ "$a" \> "$b" ]; then
    echo "$b is lexicographically smaller than $a"
else
    echo "Strings are equal"
fi

Notas:

  1. Espaços entre ife [e ]são importantes
  2. >e <são operadores de redirecionamento, portanto, escape-o com \>e \<respectivamente para cadeias.

6
Agradecimentos para a string comparação ordem alfabética
shadi

Meu problema era que, $ana verdade, o " "envolvia como parte do valor literal da string, portanto, tive que usar o caractere de escape $bpara comparar os valores. Consegui encontrar isso após a execução bash -x ./script.sh, o sinalizador -x permite que você veja o valor de cada execução e ajuda na depuração.
ShahNewazKhan

Observe que a comparação de ordem alfabética não é padronizada pelo POSIX, portanto, não é garantido que funcione em plataformas não-GNU / shells não-bash. Somente as operações em pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html são garantidas como portáteis.
22718 Charles Duffy

62

Para comparar seqüências de caracteres com caracteres curinga, use

if [[ "$stringA" == *$stringB* ]]; then
  # Do something here
else
  # Do Something here
fi

12
É importante que os curingas possam ser usados ​​apenas no lado direito! Observe também a falta "nos caracteres curinga. (btw: +1 para curingas!)
Scz

6
A expansão $stringB deve ser citado (e, aliás, do lado esquerdo não precisa ser citado): if [[ $stringA = *"$stringB"* ]]; then.
gniourf_gniourf

Estou tentando usar a mesma lógica curinga para o nome do arquivo no caminho do arquivo. Mas não está funcionando para mim. tentei todas as diferentes seqüências de caracteres curinga fornecidas aqui. mas sempre vai para outro caso. stringA no meu caso é um caminho de arquivo / tmp / file e stringB é "file".
rain

35

Eu tenho que discordar de um dos comentários em um ponto:

[ "$x" == "valid" ] && echo "valid" || echo "invalid"

Não, isso não é um delineador louco

É só que parece que um, hum, o não iniciado ...

Ele usa padrões comuns como uma linguagem, de certa forma;

E depois que você aprendeu o idioma.

Na verdade, é bom ler

É uma expressão lógica simples, com uma parte especial: avaliação lenta dos operadores lógicos.

[ "$x" == "valid" ] && echo "valid" || echo "invalid"

Cada parte é uma expressão lógica; o primeiro pode ser verdadeiro ou falso, os outros dois são sempre verdadeiros.

(
[ "$x" == "valid" ] 
&&
echo "valid"
)
||
echo "invalid"

Agora, quando é avaliado, o primeiro é verificado. Se for falso, então o segundo operando da lógica e && depois não é relevante. O primeiro não é verdadeiro, portanto, não pode ser o primeiro e o segundo, de qualquer maneira.
Agora, nesse caso, é o primeiro lado da lógica ou || falso, mas pode ser verdade se o outro lado - a terceira parte - for verdadeiro.

Portanto, a terceira parte será avaliada - principalmente escrevendo a mensagem como efeito colateral. (Tem o resultado 0para true, que não usamos aqui)

Os outros casos são semelhantes, mas mais simples - e - eu prometo! são - podem ser - fáceis de ler!
(Eu não tenho um, mas acho que ser um veterano do UNIX com barba grisalha ajuda muito nisso.)


17
A ... && ... || ...é geralmente desaprovam (greybeard pena Unix veterano, você esteve errado por todo esse tempo), como não é semanticamente equivalente a if ... then ... else .... Não se preocupe, isso é uma armadilha comum .
gniourf_gniourf

6
@gniourf_gniourf O OP não está errado - e eles provavelmente não são ignorantes, como você sugere. ... && ... || ...é um padrão perfeitamente válido e um idioma comum do bash. O uso prescreve conhecimentos prévios (o que pode ser bom ter em mente se houver iniciantes na platéia), mas o OP tem o cabelo para provar que eles sabem como evitar as tampas de bueiros abertas.
Ebpa 3/17

3
@ebpa E se a instrução a seguir && retornar um valor false, a execução prosseguirá para a instrução a seguir || ? Se assim o que está errado e, talvez, é o que gniourf está sugerindo
TSG

4
Eu pensei que eco fosse apenas um exemplo. A declaração seguinte && ainda pode retornar um valor diferente de zero
TSG

2
@gniourf_gniourf +1 por postar o link para Bash Pitfalls! Muito útil!
Jaguar

21

você também pode usar caso de uso / esac

case "$string" in
 "$pattern" ) echo "found";;
esac

Isso é equivalente ou contém?
Ytpillai

@ytpillai, é equivalência. Lembre-se de que você pode ter padrões separados por |antes do ). A ininstrução é equivalente a thenem ifinstruções. Você poderia argumentar que funciona sobre uma lista de padrões, onde cada lista tem sua própria declaração do que fazer, se você é do Python. Não gosto substring in string, mas sim for item in list. Use a *como sua última declaração se desejar uma elsecondição. Retorna no primeiro encontro.
mazunki

18

O script a seguir lê de um arquivo chamado "testonthis" linha por linha e, em seguida, compara cada linha com uma string simples, uma string com caracteres especiais e uma expressão regular. Se não corresponder, o script imprimirá a linha, caso contrário não.

O espaço no Bash é muito importante. Portanto, o seguinte funcionará:

[ "$LINE" != "table_name" ] 

Mas o seguinte não:

["$LINE" != "table_name"] 

Então, por favor, use como está:

cat testonthis | while read LINE
do
if [ "$LINE" != "table_name" ] && [ "$LINE" != "--------------------------------" ] && [[ "$LINE" =~ [^[:space:]] ]] && [[ "$LINE" != SQL* ]]; then
echo $LINE
fi
done

Use esta abordagem para passar por um arquivo. Ou seja, remova o UUoC entre outras coisas.
fedorqui 'Então pare de prejudicar'

Não é importante por causa bashmas porque [é realmente um binário externo (como em which [rendimentos algo como /usr/bin/[)
Patrick Bergner

11

Eu provavelmente usaria correspondências regexp se a entrada tiver apenas algumas entradas válidas. Por exemplo, apenas o "start" e "stop" são ações válidas.

if [[ "${ACTION,,}" =~ ^(start|stop)$ ]]; then
  echo "valid action"
fi

Observe que eu minúscula a variável $ACTIONusando as vírgulas duplas. Observe também que isso não funcionará em versões muito antigas do bash por aí.


9

Bash 4+ exemplos. Nota: não usar aspas causará problemas quando as palavras contiverem espaços, etc. Sempre cite no Bash, IMO.

Aqui estão alguns exemplos no Bash 4+:

Exemplo 1, verifique 'yes' na string (não faz distinção entre maiúsculas e minúsculas):

    if [[ "${str,,}" == *"yes"* ]] ;then

Exemplo 2, verifique 'yes' na string (não faz distinção entre maiúsculas e minúsculas):

    if [[ "$(echo "$str" | tr '[:upper:]' '[:lower:]')" == *"yes"* ]] ;then

Exemplo 3, verifique se 'yes' na string (diferencia maiúsculas de minúsculas):

     if [[ "${str}" == *"yes"* ]] ;then

Exemplo 4, verifique se 'yes' na string (diferencia maiúsculas de minúsculas):

     if [[ "${str}" =~ "yes" ]] ;then

Exemplo 5, correspondência exata (diferencia maiúsculas de minúsculas):

     if [[ "${str}" == "yes" ]] ;then

Exemplo 6, correspondência exata (sem distinção entre maiúsculas e minúsculas):

     if [[ "${str,,}" == "yes" ]] ;then

Exemplo 7, correspondência exata:

     if [ "$a" = "$b" ] ;then

Aproveitar.


para mim (mac GNU bash versão 4.4.12 (1) -release x86_64-apple-darwin17.0.0), eu tenho que usar if [ "$a"="$b" ]ou ele não funciona ... não pode ter espaços em torno dos iguais
espectro

1

Fiz dessa maneira que é compatível com Bash e Dash (sh):

testOutput="my test"
pattern="my"

case $testOutput in (*"$pattern"*)
    echo "if there is a match"
    exit 1
    ;;
(*)
   ! echo there is no coincidence!
;;esac

qual é a diferença entre usar um anterior (e não usá-lo?
mazunki
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.