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
John Feminella
fonte
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'"
Marko
fonte
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.
Guru
fonte
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
Jeffrey L. Roberts
fonte
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.)

Volker Siegel
fonte
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
ghostdog74
fonte
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
Harshil
fonte
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í.

steviethecat
fonte
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.

Mike Q
fonte
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
shades3002
fonte
qual é a diferença entre usar um anterior (e não usá-lo?
mazunki