Comment vérifier si une chaîne contient un substrat dans Bash
j'ai une chaîne de caractères dans Bash:
string="My string"
Comment puis-je tester s'il contient une autre chaîne?
if [ $string ?? 'foo' ]; then
echo "It's there!"
fi
où ??
est mon opérateur inconnu. Est-ce que j'utilise echo et grep
?
if echo "$string" | grep 'foo'; then
echo "It's there!"
fi
ça a l'air un peu maladroit.
21 réponses
vous pouvez utiliser réponse de Marcus (*wildcards) en dehors d'une déclaration de cas, aussi, si vous utilisez des doubles parenthèses:
string='My long string'
if [[ $string == *"My long"* ]]; then
echo "It's there!"
fi
notez que les espaces dans la chaîne d'aiguille doivent être placés entre les guillemets doubles, et les caractères génériques *
doivent être à l'extérieur.
si vous préférez l'approche regex:
string='My string';
if [[ $string =~ .*My.* ]]
then
echo "It's there!"
fi
Je ne suis pas sûr d'utiliser une instruction if, mais vous pouvez obtenir un effet similaire avec une instruction case:
case "$string" in
*foo*)
# Do stuff
;;
esac
réponse Compatible
comme il y a déjà beaucoup de réponses en utilisant des fonctionnalités spécifiques à Bash, il y a une façon de travailler sous des shells plus pauvres, comme busybox :
[ -z "${string##*$reqsubstr*}" ]
dans la pratique, cela pourrait donner:
string='echo "My string"'
for reqsubstr in 'o "M' 'alt' 'str';do
if [ -z "${string##*$reqsubstr*}" ] ;then
echo "String '$string' contain substring: '$reqsubstr'."
else
echo "String '$string' don't contain substring: '$reqsubstr'."
fi
done
Cela a été testé sous bash , tableau de bord , ksh et cendres (busybox), et le résultat est toujours:
String 'echo "My string"' contain substring: 'o "M'.
String 'echo "My string"' don't contain substring: 'alt'.
String 'echo "My string"' contain substring: 'str'.
en une seule fonction
comme demandé par @EeroAaltonen voici une version de la même démo, testée sous les mêmes coquillages:
myfunc() {
reqsubstr=""
shift
string="$@"
if [ -z "${string##*$reqsubstr*}" ] ;then
echo "String '$string' contain substring: '$reqsubstr'.";
else
echo "String '$string' don't contain substring: '$reqsubstr'."
fi
}
puis:
$ myfunc 'o "M' 'echo "My String"'
String 'echo "My String"' contain substring 'o "M'.
$ myfunc 'alt' 'echo "My String"'
String 'echo "My String"' don't contain substring 'alt'.
Avis: vous avez à s'échapper ou double joindre les devis et/ou des guillemets:
$ myfunc 'o "M' echo "My String"
String 'echo My String' don't contain substring: 'o "M'.
$ myfunc 'o "M' echo \"My String\"
String 'echo "My String"' contain substring: 'o "M'.
Simple "fonction de 1519410920"
cela a été testé sous busybox , dash et, bien sûr bash :
stringContain() { [ -z "${2##**}" ]; }
C'est tout!
puis maintenant:
$ if stringContain 'o "M3' 'echo "My String"';then echo yes;else echo no;fi
no
$ if stringContain 'o "M' 'echo "My String"';then echo yes;else echo no;fi
yes
... Ou si la chaîne soumise pouvait être vide, comme indiqué par @Sjlver, la fonction deviendrait:
stringContain() { [ -z "${2##**}" ] && [ -z "" -o -n "" ]; }
ou comme suggéré par Adrian Günter commentaire , en évitant -o
switche:
stringContain() { [ -z "${2##**}" ] && { [ -z "" ] || [ -n "" ] ;} ; }
à cordes vides:
$ if stringContain '' ''; then echo yes; else echo no; fi
yes
$ if stringContain 'o "M' ''; then echo yes; else echo no; fi
no
vous devez vous rappeler que le script shell est moins un langage et plus un ensemble de commandes. Instinctivement, vous pensez que ce "langage" vous oblige à suivre un if
avec un [
ou un [[
. Les deux ne sont que des commandes qui renvoient un statut de sortie indiquant un succès ou un échec (comme toutes les autres commandes). Pour cette raison , j'utiliserais grep
, et pas la commande [
.
Just do:
if grep -q foo <<<"$string"; then
echo "It's there"
fi
maintenant que vous pensez à if
comme tester le statut de sortie de la commande qui le suit (complet avec semi-colon). Pourquoi ne pas reconsidérer la source de la chaîne à tester?
## Instead of this
filetype="$(file -b "")"
if grep -q "tar archive" <<<"$filetype"; then
#...
## Simply do this
if file -b "" | grep -q "tar archive"; then
#...
l'option -q
fait que grep ne produit rien, car nous voulons seulement le code de retour. <<<
permet au shell d'étendre le mot suivant et de l'utiliser comme entrée à la commande, une version en une ligne du document <<
ici (Je ne suis pas sûr que ce soit une norme ou un bashisme).
la réponse acceptée est la meilleure, mais puisqu'il y a plus d'une façon de le faire, voici une autre solution:
if [ "$string" != "${string/foo/}" ]; then
echo "It's there!"
fi
${var/search/replace}
est $var
avec la première occurrence de search
remplacé par replace
, s'il est trouvé (il ne change pas $var
). Si vous essayez de remplacer foo
par rien, et la chaîne a changé, alors évidemment foo
a été trouvé.
donc il y a beaucoup de solutions utiles à la question - mais qui est le plus rapide / utilise le moins de ressources?
essais répétés utilisant ce cadre:
/usr/bin/time bash -c 'a=two;b=onetwothree; x=100000; while [ $x -gt 0 ]; do TEST ; x=$(($x-1)); done'
remplacer L'essai à chaque fois:
[[ $b =~ $a ]] 2.92user 0.06system 0:02.99elapsed 99%CPU
[ "${b/$a//}" = "$b" ] 3.16user 0.07system 0:03.25elapsed 99%CPU
[[ $b == *$a* ]] 1.85user 0.04system 0:01.90elapsed 99%CPU
case $b in *$a):;;esac 1.80user 0.02system 0:01.83elapsed 99%CPU
doContain $a $b 4.27user 0.11system 0:04.41elapsed 99%CPU
(doContain était dans la réponse de F. Houri)
et pour les rires:
echo $b|grep -q $a 12.68user 30.86system 3:42.40elapsed 19%CPU !ouch!
ainsi l'option de substitution simple gagne de manière prévisible si dans un test étendu ou un cas. L'étui est portable.
Tuyauterie à 100000 grep est prévisible douloureux! L'ancienne règle sur l'utilisation d'Utilités externes sans nécessité est vraie.
cela fonctionne aussi:
if printf -- '%s' "$haystack" | egrep -q -- "$needle"
then
printf "Found needle in haystack"
fi
et le test négatif est:
if ! printf -- '%s' "$haystack" | egrep -q -- "$needle"
then
echo "Did not find needle in haystack"
fi
je suppose que ce style est un peu plus classique -- moins dépendant des caractéristiques de bash shell.
l'argument --
est purement paranoïaque POSIX, utilisé pour protéger contre les chaînes d'entrée similaires aux options, telles que --abc
ou -a
.
Note: dans une boucle serrée ce code sera beaucoup plus lent que L'utilisation des caractéristiques internes de la coque de Bash, car un (ou deux) processus séparés seront créés et connectés via des tuyaux.
Que pensez-vous de ceci:
text=" <tag>bmnmn</tag> "
if [[ "$text" =~ "<tag>" ]]; then
echo "matched"
else
echo "not matched"
fi
cette réponse de débordement de pile était la seule à piéger l'espace et les caractères de tiret:
# For null cmd arguments checking
to_check=' -t'
space_n_dash_chars=' -'
[[ $to_check == *"$space_n_dash_chars"* ]] && echo found
comme Paul l'a mentionné dans sa comparaison de performances:
if echo "abcdefg" | grep -q "bcdef"; then
echo "String contains is true."
else
echo "String contains is not true."
fi
c'est compatible POSIX comme la 'case' $string 'dans' Réponse fournie par Marcus, mais est légèrement plus facile à lire que la réponse de l'énoncé de cas. Notez également que cela sera beaucoup plus lent que d'utiliser une instruction de cas, comme Paul l'a souligné, ne l'utilisez pas dans une boucle.
[[ $string == *foo* ]] && echo "It's there" || echo "Couldn't find"
est:
[ $(expr $mystring : ".*${search}.*") -ne 0 ] && echo 'yes' || echo 'no'
grep -q
est utile à cet effet.
la même chose en utilisant awk
:
string="unix-bash 2389"
character="@"
printf '%s' "$string" | awk -vc="$character" '{ if (gsub(c, "")) { print "Found" } else { print "Not Found" } }'
sortie:
Non Trouvé
string="unix-bash 2389"
character="-"
printf '%s' "$string" | awk -vc="$character" '{ if (gsub(c, "")) { print "Found" } else { print "Not Found" } }'
sortie:
Trouvé
source originale: http://unstableme.blogspot.com/2008/06/bash-search-letter-in-string-awk.html
j'aime sed.
substr="foo"
nonsub="$(echo "$string" | sed "s/$substr//")"
hassub=0 ; [ "$string" != "$nonsub" ] && hassub=1
D'Éditer, De Logique:
-
utiliser sed pour supprimer l'instance de la chaîne de caractères
-
si la nouvelle chaîne diffère de la chaîne ancienne, il existe un substrat
151990920"
My .bash_profile et comment j'ai utilisé grep si le chemin incluait mes 2 dirs bin, ne les ajoutez pas
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
U=~/.local.bin:~/bin
if ! echo "$PATH" | grep -q "home"; then
export PATH=$PATH:${U}
fi
j'ai trouvé avoir besoin de cette fonctionnalité assez fréquemment, donc j'utilise une fonction shell maison dans mon .bashrc
comme celle-ci qui me permet de la réutiliser aussi souvent que j'en ai besoin, avec un nom facile à retenir:
function stringinstring()
{
case "" in
*""*)
return 0
;;
esac
return 1
}
pour tester si $string1
(dire, abc ) est contenu dans $string2
(dire, 123abcABC ) je dois juste exécuter stringinstring "$string1" "$string2"
et vérifier la valeur de retour, par exemple
stringinstring "$str1" "$str2" && echo YES || echo NO
Essayer oobash c'est un OO-style de la bibliothèque string pour bash 4. Elle soutient les umlauts allemands. Il est écrit en bash. De nombreuses fonctions sont disponibles: -base64Decode
, -base64Encode
, -capitalize
, -center
, -charAt
, -concat
, -contains
, -count
, -endsWith
, -equals
, -equalsIgnoreCase
, -reverse
, -hashCode
, -indexOf
, -isAlnum
, -isAlpha
, -isAscii
, -isDigit
, -isEmpty
, -isHexDigit
, -isLowerCase
, -isSpace
, -isPrintable
, -isUpperCase
, -isVisible
, -lastIndexOf
, -length
, -matches
, -replaceAll
, -replaceFirst
, -startsWith
, -substring
, -swapCase
, -toLowerCase
, -toString
, -toUpperCase
, -trim
, et -zfill
.
regardez l'exemple contient:
[Desktop]$ String a testXccc
[Desktop]$ a.contains tX
true
[Desktop]$ a.contains XtX
false
mot Exact match:
string='My long string'
exactSearch='long'
if grep -E -q "\b${exactSearch}\b" <<<${string} >/dev/null 2>&1
then
echo "It's there"
fi
j'utilise cette fonction (une dépendance non incluse mais évidente). Il passe les tests indiqués ci-dessous. Si la fonction retourne une valeur > 0 alors la chaîne a été trouvée. Vous pouvez tout aussi bien retourner 1 ou 0 à la place.
function str_instr {
# Return position of ```str``` within ```string```.
# >>> str_instr "str" "string"
# str: String to search for.
# string: String to search.
typeset str string x
# Behavior here is not the same in bash vs ksh unless we escape special characters.
str="$(str_escape_special_characters "")"
string=""
x="${string%%$str*}"
if [[ "${x}" != "${string}" ]]; then
echo "${#x} + 1" | bc -l
else
echo 0
fi
}
function test_str_instr {
str_instr "(" "'foo@host (dev,web)'" | assert_eq 11
str_instr ")" "'foo@host (dev,web)'" | assert_eq 19
str_instr "[" "'foo@host [dev,web]'" | assert_eq 11
str_instr "]" "'foo@host [dev,web]'" | assert_eq 19
str_instr "a" "abc" | assert_eq 1
str_instr "z" "abc" | assert_eq 0
str_instr "Eggs" "Green Eggs And Ham" | assert_eq 7
str_instr "a" "" | assert_eq 0
str_instr "" "" | assert_eq 0
str_instr " " "Green Eggs" | assert_eq 6
str_instr " " " Green " | assert_eq 1
}
Bash4+ examples. Note: ne pas utiliser de guillemets causera des problèmes lorsque les mots contiennent des espaces, etc.. Toujours citer bash IMO.
voici quelques exemples de BASH4+:
exemple 1, cochez "Oui" dans la chaîne de caractères (insensible à la casse):
if [[ "${str,,}" == *"yes"* ]] ;then
exemple 2, cochez "Oui" dans la chaîne de caractères (insensible à la casse):
if [[ "$(echo "$str" | tr '[:upper:]' '[:lower:]')" == *"yes"* ]] ;then
exemple 3, cochez "Oui" dans la chaîne de caractères (sensible à la casse) :
if [[ "${str}" == *"yes"* ]] ;then
exemple 4, cochez "Oui" dans la chaîne de caractères (sensible à la casse):
if [[ "${str}" =~ "yes" ]] ;then
exemple 5, correspondance exacte (sensible à la casse):
if [[ "${str}" == "yes" ]] ;then
exemple 6, correspondance exacte (insensible à la casse):
if [[ "${str,,}" == "yes" ]] ;then
exemple 7, correspondance exacte:
if [ "$a" = "$b" ] ;then
de profiter de.