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
- Double possible de Test du shell pour trouver un modèle dans une chaîne
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"*
pourcase
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.