Recherche de sous-chaîne insensible à la casse dans un script shell [fermé]

22

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

Miguel Roque
la source
grep -ipeut être?
Ramesh
Comment vais-je mettre cela dans mon script? Je suis désolé s'il s'agit d'une question novice. Je commence tout juste à étudier Linux car j'en ai besoin pour mon stage. Merci!
Miguel Roque
1
Ce que vous demandez, c'est l' écriture de scripts shell - "linux" n'est pas un langage de programmation, c'est un noyau de système d'exploitation. Le shell le plus couramment utilisé avec linux est bash, qui est un surensemble de la norme unixsh . Vous pouvez commencer par regarder l'un de ces éléments: | 1 | | 2 | - juste pour avoir une idée du contexte réel.
goldilocks
1
Cette question semble maintenant assez claire et correspond aux directives du centre d'aide. Peut-il être ouvert au profit d'autrui?
BobDoolittle
2
Je ne vois pas pourquoi cette question n'est pas claire. Que dois-je ajouter pour que ce soit clair?
Miguel Roque

Réponses:

11

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 résonner it works. Essayez de remplacer echo hellopar 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' ifinstruction 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' -ioption de grep dit d'ignorer la casse.
L' -qoption dit de ne pas émettre de sortie et de quitter après la première correspondance.
L' -Foption dit de traiter l'argument comme une chaîne plutôt que comme une expression régulière.

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

BobDoolittle
la source
Je ne comprends pas pourquoi Gilles a estimé qu'il était nécessaire de changer le code auquel j'ai contribué. Il n'a rien cassé mais cela a très bien fonctionné. Vous n'avez pas besoin des guillemets doubles dans cet exemple - ils sont importants si la sortie contient des espaces cependant. Et == fonctionne aussi bien que = car sh est en fait bash sous Linux. Le Bourne Shell d'origine a disparu depuis longtemps à ce moment. Je ne pense même plus que Solaris le livre. Bien que inutile dans cet exemple, je conviens que les guillemets doubles sont probablement une meilleure pratique, mais il en va de même pour '==' à mon avis, afin de séparer clairement l'affectation et la comparaison.
BobDoolittle
Attendez, donc on peut éditer un post? Je ne le savais pas.
Miguel Roque
Avec une réputation suffisante, oui. J'espère que quelqu'un avec une grande réputation réfléchira à deux fois avant de faire des modifications inutiles, en particulier pour coder dans ce forum. unix.stackexchange.com/help/privileges
BobDoolittle
@BobDoolittle Il se peut que dans certains cas cela fasse une différence mais pas avec votre configuration - c'est bon à savoir.
2
Notez qu'en pratique, il ne s'agit pas uniquement du shell Bourne. ==n'est pas POSIX. shn'est pas bashsur tous les systèmes basés sur Linux. ==n'est pas pris en charge par ash(sur lequel shest basé au moins de nombreux BSD et dérivés Debian), ou posh, et doit être cité dans zsh. Il est inutile de doubler le =. [est une commande de test. Il n'est pas nécessaire de lever l'ambiguïté entre affectation et comparaison ici. C'est différent (( a == b ))vs (( a = b)). L'utilisation ==dans un script qui commence par #! /bin/shest incorrecte. Si vous supposez kshou la bashsyntaxe, mettez à jour en #!conséquence.
Stéphane Chazelas
49

Vous pouvez effectuer une correspondance de sous-chaîne insensible à la casse de manière native en bashutilisant l'opérateur regex =~si vous définissez l' nocasematchoption 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
tournevis
la source
6
lol! points pour la connaissance obscure de coquille.
BobDoolittle
2
Cette option affecte également l'opérateur de correspondance simple. [[ XYZ == xyz ]] && echo "match"=>match
itsadok
7

Pour une recherche de chaîne sensible à la casse de la valeur de la variable needledans 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 trdans GNU coreutils ne prend pas en charge les paramètres régionaux multi-octets (par exemple UTF-8). Pour faire fonctionner les locales multi-octets, utilisez plutôt awk. Si vous allez 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 trde BusyBox ne prend pas en charge la syntaxe; vous pouvez utiliser à la place. BusyBox ne prend pas en charge les paramètres régionaux non ASCII.[:CLASS:]tr a-z A-Z

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
Gilles 'SO- arrête d'être méchant'
la source
Je me rends compte que cela fait quelques années, mais tout cela printf | trme fait tourner la tête. Dans la mesure du possible, gardez votre appel de commandes à un minimum ... étant donné une variable v, vous pouvez accomplir la même chose en utilisant v=$(tr '[:lower:]' '[:upper:]' <<<$v). Pour ceux qui ne l'ont jamais vu auparavant, le <<<est essentiellement une "variable ici" comme l'utilisation de l' <<EOFest pour un document ici. Ne le faites pas printfou à echomoins que vous ne deviez absolument le faire.
Will
@Will Cela ne fonctionne que dans les shells qui ont l' <<<opérateur: ksh, bash, zsh, mais pas plain sh. Et c'est assez proche de la tuyauterie printfen termes de fonctionnement: il y a le même nombre d'appels vers forket execve(en supposant que cela printfsoit intégré, ce qui est le cas sur la plupart des shells); une différence est que <<<crée un fichier temporaire plutôt que d'utiliser un canal. <<<est pratique à taper mais pas une amélioration des performances.
Gilles 'SO- arrête d'être méchant'