Teste si une chaîne contient une sous-chaîne

Jai le code

file="JetConst_reco_allconst_4j2t.png" if [[ $file == *_gen_* ]]; then echo "True" else echo "False" fi 

Je teste si file contient « gen ». La sortie est « False ». Bien!

Le problème, cest quand je remplace « gen » par une variable testseq:

file="JetConst_reco_allconst_4j2t.png" testseq="gen" if [[ $file == *_$testseq_* ]]; then echo "True" else echo "False" fi 

La sortie est maintenant « True ». Comment est-ce possible? Comment résoudre le problème?

Commentaires

Réponse

Vous devez interpoler le $testseq variable de lune des manières suivantes:

  • $file == *_"$testseq"_* (ici $testseq considéré comme une chaîne fixe)

  • $file == *_${testseq}_* (ici $testseq considéré comme un modèle).

Ou le _ immédiatement après le nom de la variable sera considéré comme faisant partie de la variable « s name (cest « un caractère valide dans un nom de variable).

Commentaires

  • Bonne réponse car elle sapplique à OP, mais sans être portable (Ce nest pas une critique de la réponse fournie, juste un avertissement aux lecteurs). 😉

Réponse

Utilisez lopérat =~ ou pour faire des comparaisons dexpressions régulières:

#!/bin/bash file="JetConst_reco_allconst_4j2t.png" testseq="gen" if [[ $file =~ $testseq ]]; then echo "True" else echo "False" fi 

De cette façon, il comparera si $file a $testseq sur son contenu.

user@host:~$ ./string.sh False 

Si je change testseq="Const":

user@host:~$ ./string.sh True 

Mais, faites attention à ce que vous alimentez $testseq. Si la chaîne de caractères représente dune manière ou dune autre une expression régulière (comme [0-9] par exemple), il y a plus de chances de déclencher une « correspondance ».

Référence :

Commentaires

  • Il semble que cette réponse concerne " bash " uniquement

Réponse

file="JetConst_reco_allconst_4j2t.png" testseq="gen" case "$file" in *_"$testseq"_*) echo "True" ;; *) echo "False" esac 

Lutilisation de case ... esac est lun des moyens les plus simples deffectuer une correspondance de motif de manière portable. Il fonctionne comme une instruction « switch » dans dautres langues (bash, zsh et ksh93 vous permet également de faire des fall-through de différentes manières incompatibles). Les modèles utilisés sont les modèles de globbing de nom de fichier standard.

Le problème que vous rencontrez est dû au fait que _ est un caractère valide dans un nom de variable. Le shell verra donc *_$testseq_* comme « *_ suivi de la valeur de la variable $testseq_ et un * « . La variable $testseq_ nest pas définie, elle sera donc développée en une chaîne vide, et vous vous retrouverez avec *_*, qui correspond évidemment au $file valeur que vous avez. Vous pouvez vous attendre à obtenir True tant que le nom de fichier dans $file contient au moins un trait de soulignement.

Pour correctement délimitez le nom de la variable, utilisez "..." autour du développement: *_"$testseq"_*. Cela utiliserait la valeur de la variable sous forme de chaîne. Souhaitez-vous utiliser la valeur de la variable comme un modèle , utilisez plutôt *_${testseq}_*.

Une autre solution rapide consiste à inclure le des traits de soulignement dans la valeur de $testseq:

testseq="_gen_" 

puis utilisez simplement *"$testseq"* comme modèle (pour une comparaison de chaînes).

Commentaires

  • Le shell cherchera donc une variable $ testseq_ et ne trouvera pas et remplacez-le par une chaîne vide.
  • @Viesturs That ' s est au cœur du problème, oui.
  • Pour un recherche de sous-chaîne, il doit être *"$testseq"* pour case comme pour [[...]] (sauf pour zsh sauf si vous enable globsubst)
  • Plus simple que [ "${str##*substr*}" ] || echo True?
  • @Isaac En termes de lecture et de compréhension ' se passe, oui. Il ' est également facile d’étendre un test avec plus de cas de test sans obtenir un " if-then-elif-then-elif " spaghetti. Bien que le test dune seule chaîne de la façon dont vous montrez (si une chaîne disparaît dans une substitution) est plus court.

Réponse

Pour le moyen portable de tester si une chaîne contient une sous-chaîne, utilisez:

file="JetConst_reco_allconst_4j2t.png"; testseq="gen" [ "${file##*$testseq*}" ] || echo True Substring is present 

Ou "${file##*"$testseq"*}" pour éviter dinterpréter les caractères glob dans testseq.

Commentaires

  • Vous ' avez besoin de quelque chose comme [" $ {file ## * $ testseq *} "! = " $ file " ] car dans le tiret qui est Supprimer le plus grand modèle de préfixe.
  • Non, @NoelGrandin il ny a pas de changement sur la plupart des shells (y compris le tiret), le plus grand modèle de préfixe sera la chaîne entière si la valeur du sous-modèle de variable ($testseq) est contenue dans la valeur $file. Essayez: dash -c 'file="JetConst_reco_allconst_4j2t.png"; testseq="reco"; echo "=${file##*"$testseq"*}="' pour confirmer que le tiret supprimera toute la chaîne.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *