Cómo comparar cadenas en Bash

Respuestas:

1377

Usar variables en declaraciones if

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

Si desea hacer algo cuando no coinciden, reemplace =con !=. Puede leer más sobre las operaciones de cadena y las operaciones aritméticas en su documentación respectiva.

¿Por qué usamos citas $x?

Desea las comillas $x, porque si está vacío, su script Bash encuentra un error de sintaxis como se ve a continuación:

if [ = "valid" ]; then

Uso no estándar del ==operador

Tenga en cuenta que Bash permite ==ser utilizado para igualdad con [, pero esto no es estándar .

Utilice el primer caso en el que las comillas $xson opcionales:

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

o use el segundo caso:

if [ "$x" = "valid" ]; then
John Feminella
fuente
12
¿Cómo se relaciona eso con la respuesta aceptada dada en Error de operador inesperado ? Obtuve el mismo error al usar [ "$1" == "on" ]. Cambiar esto a ["$ 1" = "on"] resolvió el problema.
Piotr Dobrogost
78
Los espacios son necesarios.
TAAPSogeking
66
@JohnFeminella Al escribir en un script bash, debe tener un solo =y no dos.
user13107
73
Vale la pena señalar que no puede usar [ $x -eq "valid" ]. -eqes el operador de comparación para enteros, no cadenas.
craq
2
@Alex, ¿en qué casos (si alguna vez) necesito usar el patrón ["x$yes" == "xyes"], que es el prefijo de la variable y el literal de cadena con un x? ¿Es una reliquia de los viejos tiempos o es realmente necesario en algunas situaciones?
lanoxx
142

O, si no necesita otra cláusula:

[ "$x" == "valid" ] && echo "x has the value 'valid'"
Marko
fuente
71
Y si necesita una cláusula else y desea hacer una frase loca: ["$ x" == "válido"] && echo "válido" || echo "inválido"
Matt White
11
@MattWhite: esta suele ser una mala idea, ya que echopuede fallar.
gniourf_gniourf
1
incluso las trampas que pueden aparecer, formas hermosas y elegantes de marko && MattWhite
Deko
3
@gniourf_gniourf, no hay problema, uso [ "$X" == "valid" ] || ( echo invalid && false ) && echo "valid" .
12431234123412341234123
44
@ 12431234123412341234123 { echo invalid && false; }es más eficiente que ( echo invalid && false ), ya que evita pagar una subshell innecesaria.
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. Los espacios entre ify [y ]son importantes
  2. >y <son operadores de redireccionamiento, así que escapa con \>y \<respectivamente para cadenas.
Gurú
fuente
66
Gracias por la comparación de orden alfabético de cadenas
shadi
Mi problema era que $arealmente lo " "rodeaba como parte del valor literal de la cadena, por lo tanto, tuve que usar el carácter de escape $bpara comparar los valores. Pude encontrar esto después de ejecutar bash -x ./script.sh, el indicador -x le permite ver el valor de cada ejecución y ayuda en la depuración.
ShahNewazKhan
Tenga en cuenta que la comparación de orden alfabético no está estandarizada por POSIX, por lo que no se garantiza que funcione en plataformas no GNU / shells no bash. Solo las operaciones en pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html tienen garantía de ser portátiles.
Charles Duffy
62

Para comparar cadenas con comodines use

if [[ "$stringA" == *$stringB* ]]; then
  # Do something here
else
  # Do Something here
fi
Jeffrey L. Roberts
fuente
12
¡Es importante que los comodines solo se puedan usar en el lado derecho! También tenga en cuenta lo que falta "alrededor de los comodines. (por cierto: +1 para comodines!)
Scz
66
La expansión $stringB debe ser citado (y, de paso, la izquierda no tiene que ser citado): if [[ $stringA = *"$stringB"* ]]; then.
gniourf_gniourf
Estoy tratando de usar la misma lógica comodín para el nombre de archivo en la ruta del archivo. Pero no está funcionando para mí. Probé todas las cadenas comodín diferentes que se proporcionan aquí. pero siempre va al caso más. stringA en mi caso es una ruta de archivo / tmp / file y stringB es "archivo".
lluvia
35

Tengo que estar en desacuerdo con uno de los comentarios en un punto:

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

No, eso no es una línea loca loca

Es solo que parece uno para, hmm, los no iniciados ...

Utiliza patrones comunes como lenguaje, en cierto modo;

Y después de que aprendiste el idioma.

En realidad, es bueno leer

Es una expresión lógica simple, con una parte especial: evaluación perezosa de los operadores lógicos.

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

Cada parte es una expresión lógica; el primero puede ser verdadero o falso, los otros dos siempre son verdaderos.

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

Ahora, cuando se evalúa, se comprueba el primero. Si es falso, el segundo operando de la lógica y && después no es relevante. El primero no es cierto, por lo que no puede ser el primero y el segundo, de todos modos.
Ahora, en este caso es el primer lado de la lógica o || falso, pero podría ser cierto si el otro lado, la tercera parte, es verdadero.

Entonces se evaluará la tercera parte, principalmente escribiendo el mensaje como un efecto secundario. (Tiene el resultado 0verdadero, que no usamos aquí)

Los otros casos son similares, pero más simples, ¡y lo prometo! son - pueden ser - fáciles de leer!
(No tengo uno, pero creo que ser un veterano de UNIX con barba gris ayuda mucho con esto).

Volker Siegel
fuente
17
Por ... && ... || ...lo general, está mal visto (lo siento veterano de Unix de barba gris, te has equivocado todo este tiempo), ya que no es semánticamente equivalente a if ... then ... else .... No se preocupe, esta es una trampa común .
gniourf_gniourf
66
@gniourf_gniourf OP no está mal, ni es probable que sean ignorantes como sugieres. ... && ... || ...es un patrón perfectamente válido y un idioma común de bash. Su uso prescribe conocimientos previos (lo que puede ser bueno tener en cuenta si hay principiantes en la audiencia), pero OP tiene el pelo para demostrar que saben cómo evitar las tapas de alcantarillas abiertas.
ebpa
3
@ebpa ¿Qué sucede si la declaración que sigue a && devuelve un valor falso? La ejecución continuará hasta la siguiente declaración || ? Si es así, eso está mal y tal vez es lo que sugiere gniourf
TSG
44
Pensé que echo era solo un ejemplo. La declaración que sigue a && aún podría devolver un valor distinto de cero
TSG
2
@gniourf_gniourf +1 por publicar el enlace a Bash Pitfalls! ¡Muy útil!
Jaguar
21

también puedes usar use case / esac

case "$string" in
 "$pattern" ) echo "found";;
esac
ghostdog74
fuente
¿Es esto equivalencia o contiene?
Ytpillai
@ytpillai, es equivalencia. Tenga en cuenta que puede tener patrones separados por |, antes de ). La indeclaración es equivalente a thenen ifdeclaraciones. Podrías argumentar que funciona sobre una lista de patrones, donde cada lista tiene su propia declaración de qué hacer, si vienes de Python. No como substring in string, sino más bien for item in list. Use a *como su última declaración si desea una elsecondición. Regresa en el primer encuentro.
mazunki
18

El siguiente script lee un archivo llamado "testonthis" línea por línea y luego compara cada línea con una cadena simple, una cadena con caracteres especiales y una expresión regular. Si no coincide, el script imprimirá la línea, de lo contrario no.

El espacio en Bash es muy importante. Entonces lo siguiente funcionará:

[ "$LINE" != "table_name" ] 

Pero lo siguiente no lo hará:

["$LINE" != "table_name"] 

Así que 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
fuente
Use este enfoque para revisar un archivo. Es decir, elimine la UUoC entre otras cosas.
Fedorqui 'así que deja de dañar'
No es importante por bashsino porque [es en realidad un binario externo (como en which [rendimientos algo así /usr/bin/[)
Patrick Bergner
11

Probablemente usaría coincidencias regexp si la entrada tiene solo unas pocas entradas válidas. Por ejemplo, solo "iniciar" y "detener" son acciones válidas.

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

Tenga en cuenta que pongo en minúscula la variable $ACTIONusando las comas dobles. También tenga en cuenta que esto no funcionará en versiones de bash demasiado antiguas.

steviethecat
fuente
9

Bash 4+ ejemplos. Nota: no usar comillas causará problemas cuando las palabras contengan espacios, etc. Comillas siempre en Bash, IMO.

Aquí hay algunos ejemplos en Bash 4+:

Ejemplo 1, verifique 'sí' en la cadena (no distingue entre mayúsculas y minúsculas):

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

Ejemplo 2, verifique 'sí' en la cadena (no distingue entre mayúsculas y minúsculas):

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

Ejemplo 3, verifique 'sí' en la cadena (distingue entre mayúsculas y minúsculas):

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

Ejemplo 4, verifique 'sí' en la cadena (distingue entre mayúsculas y minúsculas):

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

Ejemplo 5, coincidencia exacta (mayúsculas y minúsculas):

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

Ejemplo 6, coincidencia exacta (sin distinción entre mayúsculas y minúsculas):

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

Ejemplo 7, coincidencia exacta:

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

Disfrutar.

Mike Q
fuente
para mí (mac GNU bash versión 4.4.12 (1) -release x86_64-apple-darwin17.0.0), tengo que usar if [ "$a"="$b" ]o no funciona ... no puedo tener espacios alrededor de los iguales
espectro
1

Lo hice de esta manera que es compatible con Bash y 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
sombras3002
fuente
¿Cuál es la diferencia entre usar un precedente o (no usarlo?
mazunki