2967 votes

Comment vérifier si une chaîne contient une sous-chaîne en Bash ?

J'ai une chaîne de caractères en Bash :

string="My string"

Comment puis-je tester si elle contient une autre chaîne ?

if [ $string ?? 'foo' ]; then
  echo "It's there!"
fi

Donde ?? est mon opérateur inconnu. Dois-je utiliser echo y grep ?

if echo "$string" | grep 'foo'; then
  echo "It's there!"
fi

Ça a l'air un peu maladroit.

4 votes

Bonjour, si les chaînes vides sont fausses, pourquoi considérez-vous que c'est maladroit ? C'est le seul moyen qui a fonctionné pour moi, malgré les solutions proposées.

1 votes

Vous pouvez utiliser le expr commande ici

4 votes

En voici un pour les shells posix : stackoverflow.com/questions/2829613/

4184voto

Adam Bellaire Points 42797

Vous pouvez utiliser Réponse de Marcus (* wildcards) en dehors d'une déclaration de cas, également, 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'aiguilles doivent être placés entre guillemets doubles, et que l'élément * Les caractères de remplacement doivent être en dehors. Notez également qu'un simple opérateur de comparaison est utilisé (c'est-à-dire == ), et non l'opérateur regex =~ .

167 votes

Notez également que vous pouvez inverser la comparaison en passant simplement à != dans le test. Merci pour la réponse !

2 votes

Hmm, avec ce code exact, j'obtiens [[: not found . Une idée de ce qui ne va pas ? J'utilise GNU bash, version 4.1.5(1), sur Ubuntu.

72 votes

@Jonik : Il se peut que vous manquiez le tout ou que vous l'ayez en tant que #!/bin/sh . Essayez #!/bin/bash à la place.

757voto

Matt Tardiff Points 1258

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

string='My string';

if [[ $string =~ "My" ]]; then
   echo "It's there!"
fi

2 votes

Je devais remplacer un regex egrep dans un script bash, ceci a parfaitement fonctionné !

117 votes

El =~ recherche déjà une correspondance dans l'ensemble de la chaîne ; l'opérateur .* sont inutiles. En outre, les guillemets sont généralement préférables aux barres obliques inversées : [[ $string =~ "My s" ]]

18 votes

@bukzor Les citations ont cessé de fonctionner ici à partir de Bash 3.2+ : tiswww.case.edu/php/chet/bash/FAQ E14) . Il est probablement préférable d'assigner à une variable (en utilisant des guillemets), puis de comparer. Comme ceci : re="My s"; if [[ $string =~ $re ]]

413voto

Marcus Griep Points 3010

Je ne suis pas sûr de pouvoir utiliser une instruction if, mais vous pouvez obtenir un effet similaire avec une instruction case :

case "$string" in 
  *foo*)
    # Do stuff
    ;;
esac

90 votes

C'est probablement la meilleure solution puisqu'elle est portable aux shells posix. (a.k.a. pas de bashismes)

34 votes

@technosaurus Je trouve plutôt étrange de critiquer le "bashisme" dans une question qui n'a que le tag bash :)

49 votes

P.P. Ce n'est pas tant une critique que la préférence d'une solution plus universelle par rapport à une solution plus limitée. Considérez que, des années plus tard, des gens (comme moi) s'arrêteront pour chercher cette réponse et seront peut-être heureux d'en trouver une qui est utile dans un cadre plus large que la question originale. Comme on dit dans le monde de l'Open Source : "le choix est bon !"

171voto

Mark Baker Points 2813

Vous devez vous rappeler que le scripting shell est moins un langage qu'une collection de commandes. Instinctivement, vous pensez que ce "langage" vous oblige à suivre une if avec un [ o un [[ . Ces deux commandes 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 le [ commandement.

Fais-le :

if grep -q foo <<<"$string"; then
    echo "It's there"
fi

Maintenant que vous pensez à if comme testant l'état de sortie de la commande qui la suit (avec un 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
#...

El -q permet à grep de ne rien afficher, puisque nous ne voulons que le code de retour. <<< fait en sorte que l'interpréteur de commandes développe le mot suivant et l'utilise comme entrée de la commande, une version d'une ligne de la commande << ici le document (je ne sais pas si c'est une norme ou un Bashism).

7 votes

Ils sont appelés ici les chaînes de caractères (3.6.7) Je crois que c'est du bashisme

13 votes

On peut aussi utiliser Substitution de processus if grep -q foo <(echo somefoothing); then

0 votes

Notez que echo n'est pas portable, si vous passez une variable, utilisez printf '%s' "$string à la place.

98voto

ephemient Points 87003

La réponse acceptée est la meilleure, mais comme il y a plus d'une façon de faire, voici une autre solution :

if [ "$string" != "${string/foo/}" ]; then
    echo "It's there!"
fi

${var/search/replace} es $var avec la première instance de search remplacé par replace s'il est trouvé (cela ne change rien). $var ). Si vous essayez de remplacer foo par rien, et la chaîne a changé, alors évidemment foo a été trouvé.

5 votes

La solution d'éphémère ci-dessus : > ` if [ "$string" != "${string/foo/}" ] ; then echo "It's there !" fi` est utile quand on utilise le shell de BusyBox cendres . La solution acceptée ne fonctionne pas avec BusyBox car certaines expressions régulières de bash ne sont pas implémentées.

2 votes

L'inégalité de la différence. Une pensée plutôt bizarre ! J'adore.

1 votes

Sauf si votre chaîne est 'foo'.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X