web-dev-qa-db-fra.com

Comment déterminer si une chaîne est une sous-chaîne d'une autre dans bash?

Je veux voir si une chaîne est à l'intérieur ne partie d'une autre chaîne.
par exemple.:

'ab' in 'abc' -> true
'ab' in 'bcd' -> false

Comment puis-je faire cela dans les conditions d'un script bash?

49
Lucio

Vous pouvez utiliser le formulaire ${VAR/subs}VAR contient la plus grande chaîne et subs est la sous-chaîne que vous essayez de trouver:

my_string=abc
substring=ab
if [ "${my_string/$substring}" = "$my_string" ] ; then
  echo "${substring} is not in ${my_string}"
else
  echo "${substring} was found in ${my_string}"
fi

Cela fonctionne parce que ${VAR/subs} est égal à $VAR mais que la première occurrence de la chaîne subs a été supprimée, en particulier si $VAR ne contient pas le mot subs, il ne sera pas modifié.

26
edwin

[[ "bcd" =~ "ab" ]]
[[ "abc" =~ "ab" ]]

les crochets sont pour le test, et comme il s'agit de doubles crochets, il peut donc contenir des tests supplémentaires comme =~.

Donc, vous pouvez utiliser ce formulaire quelque chose comme

var1="ab"
var2="bcd"
if [[ "$var2" =~ "$var1" ]]; then
    echo "pass"
else
    echo "fail"
fi

Edit: corrigé "= ~", s'était retourné.

47
demure

Utilisation de bash modèles de nom de fichier (également appelés modèles "glob")

substr=ab
[[ abc == *"$substr"* ]] && echo yes || echo no    # yes
[[ bcd == *"$substr"* ]] && echo yes || echo no    # no
12
glenn jackman

Les deux approches suivantes fonctionneront sur n’importe quel environnement compatible POSIX, pas seulement en bash:

substr=ab
for s in abc bcd; do
    if case ${s} in *"${substr}"*) true;; *) false;; esac; then
        printf %s\\n "'${s}' contains '${substr}'"
    else
        printf %s\\n "'${s}' does not contain '${substr}'"
    fi
done
substr=ab
for s in abc bcd; do
    if printf %s\\n "${s}" | grep -qF "${substr}"; then
        printf %s\\n "'${s}' contains '${substr}'"
    else
        printf %s\\n "'${s}' does not contain '${substr}'"
    fi
done

Les deux sorties ci-dessus:

'abc' contains 'ab'
'bcd' does not contain 'ab'

Le premier a l’avantage de ne pas générer un processus séparé grep.

Notez que j'utilise printf %s\\n "${foo}" au lieu de echo "${foo}" parce que echo pourrait modifier ${foo} s'il contient des barres obliques inverses.

10
Richard Hansen

Déclaration de cas Shell

Ceci est la solution la plus portable, fonctionnera même sur les vieux obus Bourne et Korn Shell

#!/bin/bash
case "abcd" in
    *$1*) echo "It's a substring" ;;
    *) echo "Not a substring" ;;
esac

Échantillon échantillon:

$ ./case_substr.sh "ab"                                                                                           
It's a substring
$ ./case_substr.sh "whatever"                                                                                     
Not a substring

Notez que vous n'avez pas à utiliser spécifiquement echo, vous pouvez utiliser exit 1 et exit 0 pour indiquer un succès ou un échec.

Ce que nous pourrions aussi faire, c’est créer une fonction (qui peut être utilisée dans de gros scripts si nécessaire) avec des valeurs de retour spécifiques (0 sur correspondance, 1 sur absence de correspondance):

$ ./substring_function.sh                                  
ab is substring

$ cat substring_function.sh                                
#!/bin/sh

is_substring(){
    case "$2" in
        *$1*) return 0;;
        *) return 1;;
    esac
}

main(){
   if is_substring "ab" "abcdefg"
   then
       echo "ab is substring"
   fi
}

main $@

grep

$ grep -q 'ab' <<< "abcd" && echo "it's a substring" || echo "not a substring"                                    
it's a substring

Cette approche particulière est utile avec les instructions if-else dans bash. Aussi principalement portable

AWK

$ awk '$0~/ab/{print "it is a substring"}' <<< "abcd"                                                             
it is a substring

Python

$ python -c 'import sys;sys.stdout.write("it is a substring") if "ab" in sys.stdin.read() else exit(1)' <<< "abcd"
it is a substring

Ruby

$ Ruby -e ' puts "is substring" if  ARGV[1].include? ARGV[0]'  "ab" "abcdef"                                             
is substring
6
Sergiy Kolodyazhnyy

Observez les [[ et ":

[[ $a == z* ]]   # True if $a starts with an "z" (pattern matching).
[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).

[ $a == z* ]     # File globbing and Word splitting take place.
[ "$a" == "z*" ] # True if $a is equal to z* (literal matching).

Donc, comme @glenn_jackman l'a dit, mais sachez que si vous mettez tout le second terme entre guillemets, le test passera à correspondance littérale .

Source: http://tldp.org/LDP/abs/html/comparison-ops.html

5
Campa

Semblable à la réponse d’edwin, mais avec une portabilité améliorée pour posix & ksh, et un toucher moins bruyant que celui de Richard:

substring=ab

string=abc
if [ "$string" != "${string%$substring*}" ]; then
    echo "$substring IS in $string"
else
    echo "$substring is NOT in $string"
fi

string=bcd
if [ "$string" != "${string%$substring*}" ]; then
    echo "$string contains $substring"
else
    echo "$string does NOT contain $substring"
fi

Sortie:

abc contains ab
bcd does NOT contain ab
4
laubster