IF para retornar true se uma palavra contiver uma letra específica

1

Eu preciso de uma instrução if para retornar true se uma palavra contiver uma letra específica. Por exemplo:

var="information"
if [ $var contain "i" ]; then
....
else
...
fi
    
por antiks 03.06.2017 / 11:41

4 respostas

6

Que tal usar um switch ou case da seguinte forma:

#!/bin/sh

v="information"
case $v in
    *f*)
        echo "found \"f\" in ${v}";;
    *)
        echo "no match found in ${v}"
esac
exit

Observe que, se a agulha estiver armazenada em uma variável, é importante citá-la para que não seja um padrão:

case $haystack in
  *"$needle"*) echo match
esac

Sem ele, se $needle fosse * ou ? , por exemplo, isso corresponderia a qualquer palheiro (e palheiro não vazio, respectivamente).

Em qualquer caso, $needle não precisa ser um único caractere. Ele funcionará com qualquer string.

Em muitos shells, ele até funcionaria para qualquer sequência de bytes não nulos, mesmo que eles não formassem caracteres válidos, mas nem todos quebrariam os caracteres. Por exemplo, um byte 0xc3 pode não ser encontrado dessa forma na string é codificada em UTF-8 (0xc3 0xa9) em algumas implementações. Por outro lado, algumas shells podem encontrar i dentro de ξ quando a codificação da localidade é BIG5-HKSCS, onde ξ é codificado como 0xa3 0x69 (e i é 0x69 como em ASCII).

    
por 03.06.2017 / 11:47
3

O teste [[ ... ]] do Bash sabe sobre combinações de padrões e expressões regulares:

When the == and != operators are used, the string to the right of the operator is used as a pattern and pattern matching is performed. When the =~ operator is used, the string to the right of the operator is matched as a regular expression.

Então:

s=information
if [[ $s = *i* ]] ; then echo has i ; fi

As strings entre aspas são consideradas literalmente:

if [[ $s = "*i*" ]] ; then echo is i between two asterisks ; fi

E sabe sobre regexes

if [[ $s =~ ^.*i.*$ ]] ; then echo has i ; fi

Embora, como sempre, isso também inclua correspondências que não preencham toda a string:

if [[ $s =~ i ]] ; then echo has i ; fi
    
por 03.06.2017 / 11:55
2

Uma maneira antiga (e bastante portátil) de fazer isso é usar uma declaração de caso:

var="information"
case $var in
     *i*) echo "An 'i' was found in $var";;
     * )  echo "There is no 'i' in $var";;
esac

Como uma função de uma linha:

a="information"   b="i"

one(){ case $a in (*${b}*) true;; (*) false;; esac; }

E usado com:

if one; then 
    echo "Found %b in $a"; 
else
    echo "The character '$b' was not found in the string '$a'"
fi

Outras formas válidas de realizar o mesmo teste são:

two(){ [[  $a ==   *"$b"*      ]] ; }   # Using a pattern match.
t33(){ [[  $a =~    "$b"       ]] ; }   # Extended Regex (ERE) match.
f44(){ [[  $a =~ ^.*"$b".*$    ]] ; }   # Using a ERE with limits.
f55(){ [[  ${a//[!"${b}"]}     ]] ; }   # Removing all non-matching chars.
six(){ [ ! "$a" = "${a%"$b"*}"  ] ; }   # Using char removal. 
s77(){ [[  $a =~ ^.*$          ]] ; }   # Testing if string is valid.

Todas as funções funcionam com strings válidas.
O tempo de cada função para strings de 10, 100, 1000,…, 1000000 (1Million) caracteres está abaixo:

        Number of characters in the string.
        10     100    1000    10000   100000  1000000
one  0.024m  0.036m  0.047m   0.207m   2.117m  25.363m
two  0.028m  0.030m  0.043m   0.179m   2.081m  25.337m
t33  0.044m  0.041m  0.053m   0.151m   1.757m  22.695m
f44  0.064m  0.075m  0.241m   1.864m  19.489m 198.488m
f55  0.055m  0.182m  5.275m 421.886m
six  0.043m  0.057m  0.297m  13.987m
s77  0.056m  0.061m  0.154m   1.201m  12.749m 134.774m

O número de caracteres é criado pela repetição de um caractere.
A string a ser testada é construída com algo semelhante a:

a="$1$(repeat "$2" 10**$k)$3"

O script é chamado como:

$ ./script start a ending 

A função f55 se torna muito lenta se o tamanho da string processada ficar maior que (cerca de) 1000 caracteres. O mesmo acontece com a função six para cadeias maiores que (cerca de) 10000 (10k) caracteres.

A função two é mais rápida para strings curtas e t33 (regex) é a melhor para strings mais longas.

As funções t33 a s77 mudam os tempos de execução se forem executadas como:

$ LANG=C ./script

Tudo se torna mais rápido.

É interessante notar que as funções f44 e s77 reportarão o erro * output false) se a string testada for uma string utf-8 inválida, como:

$'\x80abcde'

Exatamente como grep (o comando base para regex) faz (em uma localidade utf-8):

$ echo $'\x80abcde' | grep '^.*$'       # no output

$ (LANG=C; echo $'\x80abcde' | grep '^.*$') 
�abcde
    
por 05.06.2017 / 12:01
1

Nas condições [[ ... ]] , o lado direito de uma comparação funciona como um padrão.

if [[ $var == *i* ]] ; then
    
por 03.06.2017 / 11:55