Comparación entre mayúsculas y minúsculas de cadenas en script de shell

129

El ==operador se utiliza para comparar dos cadenas en el script de shell. Sin embargo, quiero comparar dos cadenas ignorando mayúsculas y minúsculas, ¿cómo se puede hacer? ¿Hay algún comando estándar para esto?

Sachin Chourasiya
fuente

Respuestas:

72

si tienes bash

str1="MATCH"
str2="match"
shopt -s nocasematch
case "$str1" in
 $str2 ) echo "match";;
 *) echo "no match";;
esac

de lo contrario, debe decirnos qué shell está utilizando.

alternativa, usando awk

str1="MATCH"
str2="match"
awk -vs1="$str1" -vs2="$str2" 'BEGIN {
  if ( tolower(s1) == tolower(s2) ){
    print "match"
  }
}'
ghostdog74
fuente
32
Para cualquier persona que compare cadenas que usan ifdeclaraciones, el shoptenfoque requiere que use la forma de doble [[ ]]condicional de condicional en lugar de la forma de un solo corchete [ ]. Ver también: gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html
indiv
3
La pregunta indica que ==se usa para comparar dos cadenas, pero la respuesta demuestra una comparación que no distingue entre mayúsculas y minúsculas mediante una caseinstrucción. De modo tranquilizador, la shoptsolución también permite el uso de mayúsculas y minúsculas de ==, =~y otros operadores de comparación de cadenas.
taranaki
77
Probablemente sea prudente ejecutar shopt -u nocasematchdespués de que se realice la comparación para volver al valor predeterminado de bash.
Ohad Schneider
66
Lo mejor es guardar y restaurar la nocasematchconfiguración. Agárralo y SHELLNOCASEMATCH=`shopt -p nocasematch`luego shopt -s nocasematch$SHELLNOCASEMATCH
cámbialo
2
Mejor aún: SHELLNOCASEMATCH=$(shopt -p nocasematch; true)porque shopt -psaldrá con el código 1 si la opción no está configurada, y esto puede hacer que el script se cancele si set -eestá vigente.
Todos somos Mónica
158

En Bash, puede usar la expansión de parámetros para modificar una cadena en minúsculas / mayúsculas:

var1=TesT
var2=tEst

echo ${var1,,} ${var2,,}
echo ${var1^^} ${var2^^}
alfaniner
fuente
14
Al menos una respuesta que no implique la opción de compra. Entonces puede comparar dos cadenas ignorando mayúsculas y minúsculas y en la misma prueba, compare otras dos con mayúsculas y minúsculas. Gracias
jehon
37
¿Es esto nuevo en Bash 4? Al menos en Bash 3.2.51 (usado en OS X 10.9) no funciona - la primera echodeclaración da como resultado:-bash: ${var1,,}: bad substitution
Felix Rabe
1
Tales implementaciones de comparación que no distinguen entre mayúsculas y minúsculas son propensas a problemas de localización (como el problema turco I). No sé cómo shopt -s nocasematchse implementa, pero por lo general, estas soluciones de "nivel de lenguaje" lo manejan correctamente.
Ohad Schneider
55
@Ohad Schneider, deje que los turcos se preocupen por los problemas de localización turcos, solo necesito una forma rápida y eficiente de unir las cuerdas y esto toma el pastel por un margen
huuuuuge
1
Usuarios de macOS, actualicen su versión de Bash. El tuyo está más de una década desactualizado en este momento. itnext.io/upgrading-bash-on-macos-7138bd1066ba
Jason Carter
114

Todas estas respuestas ignoran la forma más fácil y rápida de hacer esto (siempre que tenga Bash 4):

if [ "${var1,,}" = "${var2,,}" ]; then
  echo ":)"
fi

Todo lo que está haciendo allí es convertir ambas cadenas a minúsculas y comparar los resultados.

Alboroto
fuente
66
Esto solo está disponible en Bash 4 o más reciente (por ejemplo, no en Mac OS X 10.11)
d4Rk
8
@ d4Rk, razón por la cual la primera oración de mi respuesta dice "siempre que tenga Bash 4". Dicho esto, Bash 4 ha estado fuera durante más de siete años al momento de escribir este comentario, y mi propia instalación de OS X lo ha tenido durante casi ese tiempo.
Riot
@Riot lo siento, no lo noté en primer lugar. Sé que puedes instalar cualquier bash que quieras en OS X, pero el valor predeterminado es 3.2 y como mi script también debe ejecutarse en diferentes Mac, esta no es realmente una opción para mí.
d4Rk
2
@ d4Rk es comprensible: si realmente necesita garantizar la portabilidad, le sugiero que se adhiera al estándar de shell POSIX, ya que no está garantizado que encuentre ninguna versión de bash en algunos casos.
Disturbios
1
Esto es exactamente lo que estaba buscando. Debería estar más arriba =)
Robin Winslow
39

Guarde el estado de nocasematch (en caso de que alguna otra función dependa de que esté deshabilitada):

local orig_nocasematch=$(shopt -p nocasematch)
shopt -s nocasematch
[[ "foo" == "Foo" ]] && echo "match" || echo "notmatch"
$orig_nocasematch

Nota: solo use localsi está dentro de una función.

Gerry Hickman
fuente
44
Agradable porque las casedeclaraciones (incluidas las de la respuesta de ghostdog) siempre harán que mi piel se
erice
15

Una forma sería convertir ambas cadenas en superior o inferior:

test $(echo "string" | /bin/tr '[:upper:]' '[:lower:]') = $(echo "String" | /bin/tr '[:upper:]' '[:lower:]') && echo same || echo different

Otra forma sería usar grep:

echo "string" | grep -qi '^String$' && echo same || echo different
Randy Proctor
fuente
Utilicé el trmétodo en mis aplicaciones Docker-Iized basadas en Alpine (que proporciona a shtravés de busybox). Gracias.
MXWest
7

Para korn shell, uso el comando integrado typeset (-l para minúsculas y -u para mayúsculas).

var=True
typeset -l var
if [[ $var == "true" ]]; then
    print "match"
fi
Ek C.
fuente
2
Esto es mucho mejor, en términos de rendimiento, que iniciar awk o cualquier otro proceso.
Alex
1
En bash, declare -l o -u se puede usar para establecer los atributos.
Bharat
5

Muy fácil si fgrep para hacer una línea que distingue entre mayúsculas y minúsculas compare:

str1="MATCH"
str2="match"

if [[ $(fgrep -ix $str1 <<< $str2) ]]; then
    echo "case-insensitive match";
fi
Cooper F. Nelson
fuente
Sería mejor usarlo if fgrep -qix -- "$str1" <<<"$str2"; thenen su lugar.
3

Aquí está mi solución usando tr:

var1=match
var2=MATCH
var1=`echo $var1 | tr '[A-Z]' '[a-z]'`
var2=`echo $var2 | tr '[A-Z]' '[a-z]'`
if [ "$var1" = "$var2" ] ; then
  echo "MATCH"
fi
piedras333
fuente
3

greptiene una -ibandera que significa que no distingue entre mayúsculas y minúsculas, así que pídele que te diga si var2 está en var1.

var1=match 
var2=MATCH 
if echo $var1 | grep -i "^${var2}$" > /dev/null ; then
    echo "MATCH"
fi
Larry
fuente
3
no funcionará si hay caracteres especiales de expresiones regulares en var2.
haridsv
3

Para zshla sintaxis es un poco diferente, pero sigue siendo más corta que la mayoría de las respuestas aquí:

> str1='mAtCh'
> str2='MaTcH'
> [[ "$str1:u" = "$str2:u" ]] && echo 'Strings Match!'
Strings Match!
>

Esto convertirá ambas cadenas a mayúsculas antes de la comparación.


Otro método hace uso de zsh's globbing flags, que nos permite hacer uso directo de la coincidencia entre mayúsculas y minúsculas mediante el uso de la ibandera global:

setopt extendedglob
[[ $str1 = (#i)$str2 ]] && echo "Match success"
[[ $str1 = (#i)match ]] && echo "Match success"
smac89
fuente
1

shopt -s nocaseglob

ennuikiller
fuente
1

Me encontré con este gran blog / tutorial / lo que sea sobre tratar con un patrón sensible a mayúsculas y minúsculas . Los siguientes tres métodos se explican en detalle con ejemplos:

1. Convertir el patrón a minúsculas usando el comando tr

opt=$( tr '[:upper:]' '[:lower:]' <<<"$1" )
case $opt in
        sql)
                echo "Running mysql backup using mysqldump tool..."
                ;;
        sync)
                echo "Running backup using rsync tool..."
                ;;
        tar)
                echo "Running tape backup using tar tool..."
                ;;
        *)
                echo "Other options"
                ;;
esac

2. Use expresiones regulares con patrones de casos

opt=$1
case $opt in
        [Ss][Qq][Ll])
                echo "Running mysql backup using mysqldump tool..."
                ;;
        [Ss][Yy][Nn][Cc])
                echo "Running backup using rsync tool..."
                ;;
        [Tt][Aa][Rr])
                echo "Running tape backup using tar tool..."
                ;;
        *)
                echo "Other option"
                ;;
esac

3. Encienda nocasematch

opt=$1
shopt -s nocasematch
case $opt in
        sql)
                echo "Running mysql backup using mysqldump tool..."
                ;;
        sync)
                echo "Running backup using rsync tool..."
                ;;
        tar)
                echo "Running tape backup using tar tool..."
                ;;
        *)
                echo "Other option"
                ;;
esac

shopt -u nocasematch
Sherzad
fuente