175 votes

Comment savoir si une chaîne contient une autre chaîne dans POSIX sh ?

Je veux écrire un shell Unix script qui fera diverses logiques s'il y a une chaîne à l'intérieur d'une autre chaîne. Par exemple, si je suis dans un certain dossier, bifurquer. Quelqu'un pourrait-il me dire comment réaliser ceci ? Si possible, j'aimerais que cela ne soit pas spécifique à un shell (c'est-à-dire pas seulement bash) mais s'il n'y a pas d'autre moyen, je peux m'en contenter.

#!/usr/bin/env sh

if [ "$PWD" contains "String1" ]
then
    echo "String1 present"
elif [ "$PWD" contains "String2" ]
then
    echo "String2 present"
else
    echo "Else"
fi

3 votes

Je réalise que c'est vieux, mais voici quelques éléments à noter pour les futurs visiteurs : (1) C'est généralement une bonne pratique de réserver les noms de variables en SNAKE_CASE pour les variables d'environnement et les variables internes du shell. (2) La définition de CURRENT_DIR est redondant ; vous pouvez simplement utiliser $PWD .

215voto

Matt Day Points 421

Voici une autre solution. Elle utilise Expansion des paramètres des sous-chaînes POSIX Il fonctionne donc dans Bash, Dash, KornShell (ksh), Z shell (zsh), etc.

test "${string#*$word}" != "$string" && echo "$word found in $string"

Une version fonctionnalisée avec quelques exemples :

# contains(string, substring)
#
# Returns 0 if the specified string contains the specified substring,
# otherwise returns 1.
contains() {
    string="$1"
    substring="$2"
    if test "${string#*$substring}" != "$string"
    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"

3 votes

Cela ne fonctionne pas pour moi si la sous-chaîne contient des antislashs. Comme d'habitude, substring="$( printf '%q' "$2" )" sauve la journée.

0 votes

Cela correspond aussi à des substrats erronés. string = "aplha beta betaone" substring="beta" . cela correspond à la fois à betaone et dbeta, ce qui me semble erroné.

1 votes

Qu'en est-il utiliser des caractères de remplacement ? [[ $haystack == *"My needle"* ]]

115voto

Norman Ramsey Points 115730

Shell POSIX pur :

#!/bin/sh
CURRENT_DIR=`pwd`

case "$CURRENT_DIR" in
  *String1*) echo "String1 present" ;;
  *String2*) echo "String2 present" ;;
  *)         echo "else" ;;
esac

Les interpréteurs de commandes étendus tels que ksh ou bash disposent de mécanismes de correspondance sophistiqués, mais l'ancien style case est étonnamment puissant.

50voto

a.saurabh Points 145
#!/usr/bin/env sh

# Searches a subset string in a string:
# 1st arg:reference string
# 2nd arg:subset string to be matched

if echo "$1" | grep -q "$2"
then
    echo "$2 is in $1"
else 
    echo "$2 is not in $1"
fi

3 votes

Changement grep -q "$2" a grep -q "$2" > /dev/null pour éviter toute sortie indésirable.

3 votes

Changement grep -q "$2" a grep -q "$2" 2>/dev/null pour éviter toute sortie indésirable.

0 votes

grep n'est pas POSIX.

38voto

John Hyland Points 4578

Malheureusement, je n'ai pas connaissance d'un moyen de faire cela dans sh. Cependant, en utilisant bash (à partir de la version 3.0.0, qui est probablement celle que vous avez), vous pouvez utiliser l'opérateur =~ comme ceci :

#!/bin/bash
CURRENT_DIR=`pwd`

if [[ "$CURRENT_DIR" =~ "String1" ]]
then
 echo "String1 present"
elif [[ "$CURRENT_DIR" =~ "String2" ]]
then
 echo "String2 present"
else
 echo "Else"
fi

Comme bonus supplémentaire (et/ou comme avertissement, si vos chaînes de caractères contiennent des caractères bizarres), =~ accepte les regex comme opérande droit si vous laissez les guillemets.

3 votes

Ne citez pas la regex, ou elle sera pas le travail en général. Par exemple, essayez [[ test =~ "test.*" ]] vs. [[ test =~ test.* ]] .

1 votes

Eh bien, cela fonctionnera parfaitement si vous testez une sous-chaîne, comme dans la question initiale, mais il ne traitera pas l'opérande droit comme une expression rationnelle. Je vais mettre à jour ma réponse pour que ce soit plus clair.

8 votes

C'est Bash, pas POSIX sh comme le demande la question.

18voto

helpermethod Points 11015
case $(pwd) in
  *path) echo "ends with path";;
  path*) echo "starts with path";;
  *path*) echo "contains path";;
  *) echo "this is the default";;
esac

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