2010-05-13 3 views
85

Je veux écrire un script shell Unix qui fera une logique différente s'il y a une chaîne dans une autre chaîne. Par exemple, si je suis dans un certain dossier, branchez-vous. Quelqu'un pourrait-il me dire comment accomplir cela? Si possible, je voudrais faire en sorte que ceci ne soit pas spécifique à la coquille (c'est-à-dire pas seulement bash) mais s'il n'y a pas d'autre moyen que je puisse faire avec cela.Comment savoir si une chaîne contient une autre chaîne dans un script shell Unix?

#!/usr/bin/env sh 

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

Je réalise que c'est ancien, mais voici quelques points à noter pour les futurs visiteurs: (1) Il est généralement recommandé de réserver des noms de variables SNAKE_CASE pour les variables internes d'environnement et de shell. (2) La définition de 'CURRENT_DIR' est redondante; vous pouvez simplement utiliser '$ PWD'. – nyuszika7h

Répondre

119

Voici encore une autre solution. Celui-ci utilise POSIX substring parameter expansion, il fonctionne en bash, tableau de bord, ksh ...

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

Edit: C'est une excellente idée, C. Ross. Voici une version fonctionnalisés 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" 
+2

intelligent, fonctionne aussi avec [[]] – Wyrmwood

+0

Est-ce que c'est ici un moyen de le faire insensible à la casse? – CMCDragonkai

+3

Cela ne fonctionne pas pour moi si Comme d'habitude, 'substring =" $ (printf '% q' "$ 2") "' sauve le jour –

6

Il y a bash regexps. Ou il y a 'expr':

if expr "$link" : '/.*' > /dev/null; then 
    PRG="$link" 
    else 
    PRG=`dirname "$PRG"`/"$link" 
    fi 
34

Malheureusement, je ne suis pas au courant d'un moyen de le faire dans sh. Cependant, en utilisant bash (à partir de la version 3.0.0, ce qui est probablement ce 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 

En prime (et/ou un avertissement, si votre les cordes ont des caractères amusants), = ~ accepte les expressions rationnelles comme opérande de droite si vous omettez les guillemets.

+2

Ne pas citer l'expression rationnelle, ou cela ne fonctionnera pas * en général. Par exemple, essayez '[[test = ~" test. * "]]' Vs '[[test = ~ test. *]]'. – l0b0

+1

Eh bien, cela marchera très bien si vous testez une sous-chaîne, comme dans la question d'origine, mais cela ne traitera pas l'opérande correct comme une regex. Je mettrai à jour ma réponse pour le rendre plus clair. –

2

Voir la page de manuel du programme 'test'. Si vous testez juste pour l'existence d'un répertoire que vous le feriez normalement faire quelque chose comme ceci:

if test -d "String1"; then 
    echo "String1 present" 
end 

Si vous essayez réellement de faire correspondre une chaîne que vous pouvez utiliser des règles d'extension bash & wildcards ainsi:

if test -d "String*"; then 
    echo "A directory starting with 'String' is present" 
end 

Si vous avez besoin de faire quelque chose de plus complexe, vous devrez utiliser un autre programme comme expr.

+1

Il semble y avoir une double citation erronée (") dans votre deuxième exemple. –

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

shell POSIX pure:

#!/bin/sh 
CURRENT_DIR=`pwd` 

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

coquilles LIKE ksh ou bash ont des mécanismes d'adaptation de fantaisie, mais l'ancien style case est étonnamment puissant.

18
#!/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 
+1

Changer' grep -q "$ 2" '' grep -q "$ 2">/dev/null' pour éviter une sortie non désirée –

1
test $(echo "stringcontain" "ingcon" |awk '{ print index($1, $2) }') -gt 0 && echo "String 1 contain string 2" 

-> Sortie: String 1 contiennent chaîne 2

1

Si vous voulez un ksh seule méthode qui est aussi rapide que " test ", vous pouvez faire quelque chose comme:

contains() # haystack needle 
{ 
    haystack=${1/$2/} 
    if [ ${#haystack} -ne ${#1} ] ; then 
     return 1 
    fi 
    return 0 
} 

Cela fonctionne en supprimant l'aiguille dans le haystack, puis en comparant la longueur de chaîne des anciennes et nouvelles meules de foin.

+1

Ne serait-il pas possible de retourner le résultat de 'test'? [$ {# haystack} -eq $ {# 1}] '? –

10

Voici une link à diverses solutions de votre problème.

C'est mon préféré car il rend le sens lisible le plus humain:

L'étoile Wildcard Méthode

if [[ "$string" == *"$substring"* ]]; then 
    return 1 
fi 
return 0 
+0

Très bien, et très lisible. – kiwicomb123

2

Dans des cas particuliers où vous voulez trouver si un mot est contenu dans une longue texte, vous pouvez parcourir le long texte avec une boucle.

found=F 
query_word=this 
long_string="many many words in this text" 
for w in $long_string; do 
    if [ "$w" = "$query_word" ]; then 
      found=T 
      break 
    fi 
done 

Ceci est un shell Bourne pur.

Questions connexes