Como determinar se uma string é uma substring de outra em bash?

43

Eu quero ver se uma string está dentro de uma parte de outra string.
por exemplo:

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

Como posso fazer isso em uma condição de um script bash?

    
por Lucio 25.05.2013 / 01:35

7 respostas

24

Você pode usar o formulário ${VAR/subs} , em que VAR contém a string maior e subs é a substring que você está tentando encontrar:

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

Isso funciona porque ${VAR/subs} é igual a $VAR , mas com a primeira ocorrência da string subs removida, especialmente se $VAR não contiver a palavra subs , não será modificada. / p>     

por edwin 25.05.2013 / 01:54
42

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

os colchetes são para o teste, e como é colchetes duplos, pode ser que alguns testes extras como =~ .

Então você poderia usar este formulário como

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

Editar: corrigido "= ~", invertido.

    
por demure 25.05.2013 / 01:56
12

Usando padrões de nome de arquivo do bash (também conhecidos como padrões "glob")

substr=ab
[[ abc == *"$substr"* ]] && echo yes || echo no    # yes
[[ bcd == *"$substr"* ]] && echo yes || echo no    # no
    
por glenn jackman 25.05.2013 / 20:12
10

As duas abordagens a seguir funcionarão em qualquer ambiente compatível com POSIX, não apenas no 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

Ambas as saídas acima:

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

O primeiro tem a vantagem de não gerar um processo grep separado.

Observe que eu uso printf %s\n "${foo}" em vez de echo "${foo}" porque echo pode mangle ${foo} se contiver barras invertidas.

    
por Richard Hansen 30.05.2013 / 01:01
5

Cuidado com o [[ e o " :

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

Assim como @glenn_jackman disse, mas lembre-se de que, se você colocar o segundo termo inteiro entre aspas, ele alternará o teste para a correspondência literal .

Fonte: link

    
por Campa 29.05.2013 / 08:36
5

instrução de caso de shell

Esta é a solução mais portável, funcionará até mesmo em velhos invólucros Bourne e casca Korn

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

Execução da amostra:

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

Observe que você não precisa usar especificamente echo para usar exit 1 e exit 0 para indicar sucesso ou falha.

O que poderíamos fazer também é criar uma função (que pode ser usada em grandes scripts, se necessário) com valores de retorno específicos (0 na correspondência, 1 na não correspondência):

$ ./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

Essa abordagem específica é útil com instruções if-else em bash . Também principalmente portátil

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
    
por Sergiy Kolodyazhnyy 24.12.2016 / 22:33
3

Semelhante à resposta da edwin, mas com melhor portabilidade para posix & ksh, e um toque menos barulhento que o 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

Saída:

abc contains ab
bcd does NOT contain ab
    
por laubster 07.01.2015 / 18:42