Pesquisa de subseqüência insensível a maiúsculas e minúsculas em um script de shell [closed]

16

Como posso escrever um script de shell que faça uma correspondência de substring sem diferenciação de maiúsculas e minúsculas na saída do comando?

    
por Miguel Roque 29.05.2014 / 03:43

3 respostas

8

Primeiro, aqui está um script de exemplo simples que não ignora maiúsculas e minúsculas:

#!/bin/bash
if [ $(echo hello) == hello ]; then
    echo it works
fi

Tente alterar a cadeia olá à direita e não deverá mais ecoar it works . Tente substituir echo hello por um comando de sua escolha. Se você quiser ignorar maiúsculas e minúsculas e nenhuma string contiver uma quebra de linha, você pode usar o grep:

#!/bin/bash
if echo Hello | grep -iqF hello; then
    echo it works
fi

A chave aqui é que você está canalizando uma saída de comando para grep . A instrução if testa o status de saída do comando mais à direita em um pipeline - nesse caso, grep. Grep sai com sucesso se e somente se encontrar uma correspondência.

A opção -i do grep diz para ignorar o caso.
A opção -q diz para não emitir saída e sair após a primeira partida.
A opção -F diz tratar o argumento como uma string em vez de uma expressão regular.

Observe que o primeiro exemplo usa [ expression ] , o que permite comparações diretas e vários operadores úteis. A segunda forma apenas executa comandos e testa seu status de saída.

    
por 29.05.2014 / 04:00
43

Você pode fazer a substring sem diferenciação de maiúsculas e minúsculas corresponder nativamente em bash usando o operador regex =~ se você definir a opção nocasematch shell. Por exemplo

s1="hElLo WoRlD"
s2="LO"

shopt -s nocasematch

[[ $s1 =~ $s2 ]] && echo "match" || echo "no match"
match

s1="gOoDbYe WoRlD"
[[ $s1 =~ $s2 ]] && echo "match" || echo "no match"
no match
    
por 29.05.2014 / 04:20
6

Para uma pesquisa de string com diferenciação de maiúsculas e minúsculas do valor da variável needle no valor da variável haystack :

case "$haystack" in
  *"$needle"*) echo "present";
  *) echo "absent";
esac

Para uma pesquisa de string sem distinção entre maiúsculas e minúsculas, converta ambos para o mesmo caso.

uc_needle=$(printf %s "$needle" | tr '[:lower:]' '[:upper:]' ; echo .); uc_needle=${uc_needle%.}
uc_haystack=$(printf %s "$haystack" | tr '[:lower:]' '[:upper:]' ; echo .); uc_haystack=${uc_haystack%.}
case "$uc_haystack" in
  *"$uc_needle"*) echo "present";;
  *) echo "absent";;
esac

Observe que o tr no GNU coreutils não suporta códigos de idioma multibyte (por exemplo, UTF-8). Para fazer o trabalho com localidades multibyte, use o awk. Se você for usar o awk, pode fazer a comparação de strings e não apenas a conversão.

if awk 'BEGIN {exit !index(toupper(ARGV[2]), toupper(ARGV[1]))}' "$needle" "$haystack"; then
  echo "present"
else
  echo "absent"
fi

O tr do BusyBox não suporta a sintaxe [:CLASS:] ; você pode usar tr a-z A-Z . O BusyBox não suporta localidades não-ASCII.

No bash (mas não no sh), existe uma sintaxe incorporada para a conversão de maiúsculas e minúsculas e uma sintaxe mais simples para correspondência de cadeias de caracteres.

if [[ "${haystack^^}" = *"${needle^^}"* ]]; then
  echo "present"
else
  echo "absent"
esac
    
por 29.05.2014 / 04:42