J'ai une chaîne 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
Cela semble un peu maladroit.
Vous pouvez utiliser la réponse de Marcus (* caractères génériques) en dehors d'une instruction de casse, aussi, si vous utilisez des doubles crochets:
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 guillemets et que 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
Comme il existe déjà de nombreuses réponses utilisant les fonctionnalités spécifiques à Bash, il existe un moyen de travailler sous des shells moins riches, comme busybox :
[ -z "${string##*$reqsubstr*}" ]
En 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 , tiret , ksh et ash (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'.
Comme demandé par @EeroAaltonen, voici une version de la même démo, testée sous les mêmes shells:
myfunc() {
reqsubstr="$1"
shift
string="$@"
if [ -z "${string##*$reqsubstr*}" ] ;then
echo "String '$string' contain substring: '$reqsubstr'.";
else
echo "String '$string' don't contain substring: '$reqsubstr'."
fi
}
Ensuite:
$ 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'.
Remarque: vous devez échapper ou doubler des guillemets 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'.
Cela a été testé sous busybox , tiret et, bien sûr bash :
stringContain() { [ -z "${2##*$1*}" ]; }
C'est tout les gens!
Alors 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 l'a souligné @Sjlver, la fonction deviendrait:
stringContain() { [ -z "${2##*$1*}" ] && [ -z "$1" -o -n "$2" ]; }
ou comme suggéré par le commentaire d'Adrian Günter , en évitant le -o
switche:
stringContain() { [ -z "${2##*$1*}" ] && { [ -z "$1" ] || [ -n "$2" ] ;} ; }
Avec des chaînes vides:
$ if stringContain '' ''; then echo yes; else echo no; fi
yes
$ if stringContain 'o "M' ''; then echo yes; else echo no; fi
no
N'oubliez pas que les scripts Shell sont moins un langage que des ensembles de commandes. Instinctivement, vous pensez que cette "langue" vous oblige à suivre une if
avec un [
ou un [[
. Ce ne sont que des commandes qui renvoient un état de sortie indiquant le succès ou l’échec (comme toutes les autres commandes). Pour cette raison, j'utiliserais grep
et non la commande [
.
Il suffit de faire:
if grep -q foo <<<"$string"; then
echo "It's there"
fi
Maintenant que vous pensez à if
, vous testez l'état de sortie de la commande qui la suit (avec le point-virgule). Pourquoi ne pas reconsidérer la source de la chaîne que vous testez?
## Instead of this
filetype="$(file -b "$1")"
if grep -q "tar archive" <<<"$filetype"; then
#...
## Simply do this
if file -b "$1" | grep -q "tar archive"; then
#...
L'option -q
fait que grep ne génère rien, car nous ne voulons que le code de retour. <<<
oblige le shell à développer le prochain mot et à l'utiliser comme entrée de la commande, une version d'une ligne du document <<
here (je ne suis pas sûr qu'il s'agisse d'un standard ou d'un bashisme).
La réponse acceptée est la meilleure, mais comme il existe 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 instance de search
remplacée par replace
, si elle est trouvée (elle ne change pas $var
). Si vous essayez de remplacer foo
par rien, et que la chaîne a changé, alors évidemment foo
a été trouvé.
Il y a donc beaucoup de solutions utiles à la question - mais laquelle est la plus rapide/utilise le moins de ressources?
Tests répétés en 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 TEST à 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 rire
echo $b|grep -q $a 12.68user 30.86system 3:42.40elapsed 19%CPU !ouch!
Donc, l'option de substitution simple l'emporte de manière préditable, que ce soit dans un test étendu ou dans un cas. L'affaire est portable.
Piper à 100 000 greps est prévisible douloureux! L'ancienne règle sur l'utilisation d'utilitaires 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 fonctionnalités de Bash Shell.
L'argument --
est une pure paranoïa POSIX, utilisé pour se protéger contre les chaînes d'entrée similaires aux options, telles que --abc
ou -a
.
Remarque: dans une boucle étroite, ce code sera beaucoup plus lent que l'utilisation des fonctions internes de Bash Shell, puisqu'un ou deux processus distincts seront créés et connectés via des tuyaux.
Que dis-tu de ça:
text=" <tag>bmnmn</tag> "
if [[ "$text" =~ "<tag>" ]]; then
echo "matched"
else
echo "not matched"
fi
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
Ceci est conforme à POSIX comme la "case" $ string "dans la réponse fournie par Marcus, mais est légèrement plus facile à lire que la réponse à la déclaration case. Notez également que cela sera beaucoup plus lent que d'utiliser une déclaration de casse, comme Paul l'a souligné, ne l'utilisez pas en boucle.
Bash4 + exemples. Remarque: ne pas utiliser de guillemets causera des problèmes lorsque les mots contiennent des espaces, etc. Toujours citer entre guillemets dans IMO.
Voici quelques exemples BASH4 +:
Exemple 1, recherchez «oui» dans la chaîne (insensible à la casse):
if [[ "${str,,}" == *"yes"* ]] ;then
Exemple 2, recherchez «oui» dans la chaîne (insensible à la casse):
if [[ "$(echo "$str" | tr '[:upper:]' '[:lower:]')" == *"yes"* ]] ;then
Exemple 3, recherchez «oui» dans la chaîne (sensible à la casse):
if [[ "${str}" == *"yes"* ]] ;then
Exemple 4, recherchez «oui» dans la chaîne (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
Exemple 8, correspondance avec caractère générique .ext (insensible à la casse):
if echo "$a" | egrep -iq "\.(mp[3-4]|txt|css|jpg|png)" ; then
prendre plaisir.
Cette réponse au débordement de pile était la seule à intercepter l'espace et les caractères tiret:
# For null cmd arguments checking
to_check=' -t'
space_n_dash_chars=' -'
[[ $to_check == *"$space_n_dash_chars"* ]] && echo found
L'un est:
[ $(expr $mystring : ".*${search}.*") -ne 0 ] && echo 'yes' || echo 'no'
[[ $string == *foo* ]] && echo "It's there" || echo "Couldn't find"
grep -q
est utile à cet effet.
La même chose avec awk
:
string="unix-bash 2389"
character="@"
printf '%s' "$string" | awk -vc="$character" '{ if (gsub(c, "")) { print "Found" } else { print "Not Found" } }'
Sortie:
Pas trouvé
string="unix-bash 2389"
character="-"
printf '%s' "$string" | awk -vc="$character" '{ if (gsub(c, "")) { print "Found" } else { print "Not Found" } }'
Sortie:
A trouvé
Source originale: http://unstableme.blogspot.com/2008/06/bash-search-letter-in-string-awk.html
Mon .bash_profile et comment j'ai utilisé grep Si le PATH incluait mes 2 répertoires
# .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'aime sed.
substr="foo"
nonsub="$(echo "$string" | sed "s/$substr//")"
hassub=0 ; [ "$string" != "$nonsub" ] && hassub=1
Edit, Logic:
Utilisez sed pour supprimer une instance de sous-chaîne d'une chaîne
Si la nouvelle chaîne diffère de l'ancienne chaîne, la sous-chaîne existe
J'ai eu besoin de cette fonctionnalité assez fréquemment, alors j'utilise une fonction Shell faite maison dans mon .bashrc
comme ceci, ce qui me permet de la réutiliser aussi souvent que nécessaire, avec un nom facile à retenir:
function stringinstring()
{
case "$2" in
*"$1"*)
return 0
;;
esac
return 1
}
Pour tester si $string1
(par exemple, abc ) est contenu dans $string2
(par exemple, 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
Essayez oobash car il s'agit d'une bibliothèque de chaînes de style OO pour bash 4. Il prend en charge les trémas allemands. C'est écrit en bash. Plusieurs fonctions sont disponibles: -base64Decode
, -base64Encode
, -capitalize
, -center
, -charAt
, -concat
, -contains
, _ [SOMECODE] ] _, -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
Correspondance exacte du mot:
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 ci-dessous. Si la fonction renvoie une valeur> 0, la chaîne a été trouvée. Vous pouvez tout aussi facilement renvoyer 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 "${1}")"
string="${2}"
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
}
Extension de la question à laquelle vous avez répondu ici https://stackoverflow.com/a/8811800/712666
Cette solution fonctionne avec des caractères spéciaux:
# contains(string, substring)
#
# Returns 0 if the specified string contains the specified substring,
# otherwise returns 1.
contains() {
string="$1"
substring="$2"
if echo "$string" | $(type -p ggrep grep | head -1) -F -- "$substring" >/dev/null; then
return 0 # $substring is in $string
else
return 1 # $substring is not in $string
fi
}
contains "abcd" "e" || echo "abcd does not contain e"
contains "abcd" "ab" && echo "abcd contains ab"
contains "abcd" "bc" && echo "abcd contains bc"
contains "abcd" "cd" && echo "abcd contains cd"
contains "abcd" "abcd" && echo "abcd contains abcd"
contains "" "" && echo "empty string contains empty string"
contains "a" "" && echo "a contains empty string"
contains "" "a" || echo "empty string does not contain a"
contains "abcd efgh" "cd ef" && echo "abcd efgh contains cd ef"
contains "abcd efgh" " " && echo "abcd efgh contains a space"
contains "abcd [efg] hij" "[efg]" && echo "abcd [efg] hij contains [efg]"
contains "abcd [efg] hij" "[effg]" || echo "abcd [efg] hij does not contain [effg]"
contains "abcd *efg* hij" "*efg*" && echo "abcd *efg* hij contains *efg*"
contains "abcd *efg* hij" "d *efg* h" && echo "abcd *efg* hij contains d *efg* h"
contains "abcd *efg* hij" "*effg*" || echo "abcd *efg* hij does not contain *effg*"