Comparaison insensible à la casse des chaînes dans le script shell

129

L' ==opérateur est utilisé pour comparer deux chaînes dans un script shell. Cependant, je veux comparer deux chaînes en ignorant la casse, comment cela peut-il être fait? Existe-t-il une commande standard pour cela?

Sachin Chourasiya
la source

Réponses:

72

si vous avez bash

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

sinon, vous devez nous dire quel shell vous utilisez.

alternative, en utilisant awk

str1="MATCH"
str2="match"
awk -vs1="$str1" -vs2="$str2" 'BEGIN {
  if ( tolower(s1) == tolower(s2) ){
    print "match"
  }
}'
ghostdog74
la source
32
Pour quiconque compare des chaînes en utilisant if instructions, l' shoptapproche vous oblige à utiliser la forme double crochet [[ ]]de conditionnel au lieu de la forme simple crochet [ ]. Voir aussi: gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html
indiv
3
La question indique que == est utilisé pour comparer deux chaînes, mais la réponse démontre une comparaison insensible à la casse à l'aide d'une caseinstruction. Rassura la shoptsolution permet également l' utilisation de la casse de ==, =~et d' autres opérateurs de comparaison de chaînes.
taranaki
7
Il est probablement judicieux d'exécuter une shopt -u nocasematchfois la comparaison effectuée pour revenir à la valeur par défaut de bash.
Ohad Schneider
6
Il est préférable d'enregistrer et de restaurer le nocasematchparamètre. Prenez-le avec SHELLNOCASEMATCH=`shopt -p nocasematch`puis changez-le avec shopt -s nocasematchet une fois terminé, restaurez-le avec$SHELLNOCASEMATCH
Urhixidur
2
Mieux encore:, SHELLNOCASEMATCH=$(shopt -p nocasematch; true)car se shopt -pterminera avec le code 1 si l'option n'est pas définie, et cela peut entraîner l'abandon du script s'il set -eest en vigueur.
We Are All Monica
158

Dans Bash, vous pouvez utiliser l'expansion des paramètres pour modifier une chaîne en minuscules / majuscules:

var1=TesT
var2=tEst

echo ${var1,,} ${var2,,}
echo ${var1^^} ${var2^^}
alphanin
la source
14
Au moins une réponse qui n'implique pas l'option shopt. Ainsi, vous pouvez comparer deux chaînes en ignorant la casse et dans le même test, comparer deux autres avec la casse. Merci
jehon
37
Est-ce nouveau dans Bash 4? Au moins dans Bash 3.2.51 (utilisé sous OS X 10.9), cela ne fonctionne pas - la première echoinstruction entraîne:-bash: ${var1,,}: bad substitution
Felix Rabe
1
De telles implémentations de comparaison insensibles à la casse sont sujettes à des problèmes de localisation (tels que le problème turc I). Je ne sais pas comment shopt -s nocasematchest implémenté mais généralement de telles solutions «au niveau du langage» le gèrent correctement.
Ohad Schneider
5
@Ohad Schneider, laissez les Turcs s'inquiéter des problèmes de localisation turque, j'ai juste besoin d'un moyen rapide et efficace de faire correspondre les cordes et cela prend le gâteau par une marge
énorme
1
Utilisateurs de macOS, mettez à niveau votre version de Bash. Le vôtre est dépassé de plus d'une décennie à ce stade. itnext.io/upgrading-bash-on-macos-7138bd1066ba
Jason Carter
114

Toutes ces réponses ignorent le moyen le plus simple et le plus rapide de le faire (tant que vous avez Bash 4):

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

Tout ce que vous faites ici est de convertir les deux chaînes en minuscules et de comparer les résultats.

Émeute
la source
6
Ceci n'est disponible que dans Bash 4 ou plus récent (par exemple pas sur Mac OS X 10.11)
d4Rk
8
@ d4Rk c'est pourquoi la première phrase de ma réponse dit "tant que vous avez Bash 4". Cela dit, Bash 4 est sorti depuis plus de sept ans au moment de la rédaction de ce commentaire, et ma propre installation OS X l'a depuis presque aussi longtemps.
Riot
@Riot désolé, je n'ai pas remarqué cela en premier lieu. Je sais que vous pouvez installer tout bash que vous voulez sur OS X, mais la valeur par défaut est 3.2 et comme mon script doit également fonctionner sur différents Mac, ce n'est pas vraiment une option pour moi.
d4Rk
2
@ d4Rk c'est compréhensible - si vous avez vraiment besoin de garantir la portabilité, je vous suggère de vous en tenir au standard du shell POSIX, car vous n'êtes pas assuré de trouver une version de bash dans certains cas.
Riot
1
Ceci est exactement ce que je cherchais. Devrait être plus haut =)
Robin Winslow
39

Enregistrez l'état de nocasematch (au cas où une autre fonction dépendrait de sa désactivation):

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

Remarque: à n'utiliser que localsi c'est à l'intérieur d'une fonction.

Gerry Hickman
la source
4
caseBien parce que les déclarations (y compris celles de la réponse de Ghostdog) feront toujours ramper ma peau
SeldomNeedy
15

Une façon serait de convertir les deux chaînes en haut ou en bas:

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

Une autre façon serait d'utiliser grep:

echo "string" | grep -qi '^String$' && echo same || echo different
Randy Proctor
la source
J'ai utilisé la trméthode dans mes applications docker-ized basées sur alpine (qui fournit shvia busybox). Je vous remercie.
MXWest
7

Pour le shell korn, j'utilise la commande intégrée de typeset (-l pour les minuscules et -u pour les majuscules).

var=True
typeset -l var
if [[ $var == "true" ]]; then
    print "match"
fi
Ek C.
la source
2
C'est bien meilleur, en termes de performances, que de démarrer awk ou tout autre processus.
Alex
1
Dans bash, declare -l ou -u peut être utilisé pour définir les attributs.
Bharat le
5

Très facile si vous fgrep de faire une comparaison de ligne insensible à la casse:

str1="MATCH"
str2="match"

if [[ $(fgrep -ix $str1 <<< $str2) ]]; then
    echo "case-insensitive match";
fi
Cooper F. Nelson
la source
Il serait préférable d'utiliser à la if fgrep -qix -- "$str1" <<<"$str2"; thenplace.
3

Voici ma solution en utilisant 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
pierres333
la source
3

grepa un -idrapeau qui signifie insensible à la casse, alors demandez-lui de vous dire si var2 est dans var1.

var1=match 
var2=MATCH 
if echo $var1 | grep -i "^${var2}$" > /dev/null ; then
    echo "MATCH"
fi
Larry
la source
3
ne fonctionnera pas s'il y a des caractères spéciaux regex dans var2.
haridsv
3

Car zshla syntaxe est légèrement différente, mais toujours plus courte que la plupart des réponses ici:

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

Cela convertira les deux chaînes en majuscules avant la comparaison.


Une autre méthode utilise zsh's globbing flags, ce qui nous permet d'utiliser directement la correspondance insensible à la casse en utilisant l' iindicateur glob:

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

shopt -s nocaseglob

ennuikiller
la source
1

Je suis tombé sur ce super blog / tutoriel / quoi que ce soit sur le traitement des motifs sensibles à la casse . Les trois méthodes suivantes sont expliquées en détail avec des exemples:

1. Convertissez le motif en minuscules à l'aide de la commande 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. Utilisez des expressions régulières avec des modèles de cas

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. Activez 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
la source