web-dev-qa-db-fra.com

Recherche de sous-chaîne insensible à la casse dans un script Shell

Comment puis-je écrire un script Shell qui fera une correspondance de sous-chaîne insensible à la casse de la sortie de la commande?

22
Miguel Roque

Voici d'abord un exemple de script simple qui n'ignore pas la casse:

#!/bin/bash
if [ $(echo hello) == hello ]; then
    echo it works
fi

Essayez de changer la chaîne bonjour à droite, et elle ne devrait plus faire écho à it works. Essayez de remplacer echo hello Par une commande de votre choix. Si vous souhaitez ignorer la casse et qu'aucune chaîne ne contient de saut de ligne, vous pouvez utiliser grep:

#!/bin/bash
if echo Hello | grep -iqF hello; then
    echo it works
fi

La clé ici est que vous dirigez une sortie de commande vers grep. L'instruction if teste l'état de sortie de la commande la plus à droite dans un pipeline - dans ce cas grep. Grep sort avec succès si et seulement s'il trouve une correspondance.

L'option -i De grep dit d'ignorer la casse.
L'option -q Dit de ne pas émettre de sortie et de quitter après la première correspondance.
L'option -F Dit de traiter l'argument comme une chaîne plutôt que comme une expression régulière.

Notez que le premier exemple utilise [ expression ] Qui permet des comparaisons directes et divers opérateurs utiles. Le second formulaire exécute simplement les commandes et teste leur état de sortie.

12
BobDoolittle

Vous pouvez faire une correspondance de sous-chaîne insensible à la casse en natif dans bash en utilisant l'opérateur regex =~ si vous définissez l'option nocasematch Shell. Par exemple

s1="hElLo WoRlD"
s2="LO"

shopt -s nocasematch

[[ $s1 =~ $s2 ]] && echo "match" || echo "no match"
match

s1="gOoDbYe WoRlD"
[[ $s1 =~ $s2 ]] && echo "match" || echo "no match"
no match
49
steeldriver

Pour une recherche de chaîne sensible à la casse de la valeur de la variable needle dans la valeur de la variable haystack:

case "$haystack" in
  *"$needle"*) echo "present";
  *) echo "absent";
esac

Pour une recherche de chaîne insensible à la casse, convertissez les deux dans la même casse.

uc_needle=$(printf %s "$needle" | tr '[:lower:]' '[:upper:]' ; echo .); uc_needle=${uc_needle%.}
uc_haystack=$(printf %s "$haystack" | tr '[:lower:]' '[:upper:]' ; echo .); uc_haystack=${uc_haystack%.}
case "$uc_haystack" in
  *"$uc_needle"*) echo "present";;
  *) echo "absent";;
esac

Notez que tr in GNU coreutils ne prend pas en charge les paramètres régionaux multi-octets (par exemple UTF-8). Pour faire fonctionner les paramètres régionaux multi-octets, utilisez plutôt awk. Si vous allez pour utiliser awk, vous pouvez lui faire faire la comparaison de chaînes et pas seulement la conversion.

if awk 'BEGIN {exit !index(toupper(ARGV[2]), toupper(ARGV[1]))}' "$needle" "$haystack"; then
  echo "present"
else
  echo "absent"
fi

Le tr de BusyBox ne prend pas en charge le [:CLASS:] syntaxe; vous pouvez utiliser tr a-z A-Z au lieu. BusyBox ne prend pas en charge les paramètres régionaux non ASCII.

Dans bash (mais pas sh), la version 4.0+, il existe une syntaxe intégrée pour la conversion de casse et une syntaxe plus simple pour la correspondance des chaînes.

if [[ "${haystack^^}" = *"${needle^^}"* ]]; then
  echo "present"
else
  echo "absent"
esac