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

?? 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.

1831
demandé sur codeforester 2008-10-23 16:37:31

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.

2618
répondu Adam Bellaire 2018-10-05 14:14:14

si vous préférez l'approche regex:

string='My string';

if [[ $string =~ .*My.* ]]
then
   echo "It's there!"
fi
400
répondu Matt Tardiff 2008-10-23 20:10:53

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
246
répondu Marcus Griep 2008-10-23 12:47:04

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 :

[ -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 , , et (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 , et, bien sûr :

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

147
répondu F. Hauri 2018-04-12 06:35:38

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).

119
répondu Mark Baker 2018-04-12 06:41:24

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é.

75
répondu ephemient 2013-06-12 05:33:48

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.

34
répondu Paul Hedderly 2014-08-27 19:42:38

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.

23
répondu kevinarpe 2015-06-11 23:53:20

Que pensez-vous de ceci:

text="   <tag>bmnmn</tag>  "
if [[ "$text" =~ "<tag>" ]]; then
   echo "matched"
else
   echo "not matched"
fi
12
répondu bn. 2014-12-15 16:37:57

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
9
répondu Yordan Georgiev 2017-05-23 12:34:48

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.

8
répondu Samuel 2014-12-31 22:32:14
[[ $string == *foo* ]] && echo "It's there" || echo "Couldn't find"
7
répondu Jahid 2015-04-28 19:55:58

est:

[ $(expr $mystring : ".*${search}.*") -ne 0 ] && echo 'yes' ||  echo 'no'
7
répondu chemila 2016-02-13 17:31:54

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

4
répondu nyuszika7h 2015-03-28 16:54:12

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"
4
répondu ride 2016-03-05 14:42:02

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
4
répondu Leslie Satenstein 2017-01-14 05:36:44

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
3
répondu Kurt Pfeifle 2014-06-11 18:09:46

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      

oobash est disponible à Sourceforge.net .

2
répondu andreas 2014-04-08 15:03:21

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
2
répondu Eduardo Cuomo 2016-11-10 14:56:18

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
}
1
répondu Ethan Post 2018-04-11 02:09:50

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.

0
répondu Mike Q 2018-10-05 18:54:36