Pesquisa de substring que não diferencia maiúsculas de minúsculas em um script de shell [fechado]

22

Como escrever um script de shell que fará uma correspondência de substring que não diferencia maiúsculas de minúsculas da saída do comando?

Miguel Roque
fonte
grep -italvez?
Ramesh 29/05
Como vou colocar isso dentro do meu script? Me desculpe se esta é uma pergunta para iniciantes. Estou apenas começando a estudar Linux porque preciso dele para o meu estágio. Obrigado!
Miguel Roque
1
O que você está perguntando é sobre scripts de shell - "linux" não é uma linguagem de programação, é um kernel do sistema operacional. O shell mais comumente usado com o linux é bash, que é um superconjunto do padrão unixsh . Você pode começar olhando para um destes: | 1 | 2 - apenas para entender o contexto atual.
goldilocks
1
Agora, essa pergunta parece bastante clara e corresponde às diretrizes da Central de Ajuda. Por favor, pode ser aberto para o benefício de outras pessoas?
precisa
2
Não vejo o porquê dessa pergunta não estar clara. O que devo adicionar para que fique claro?
Miguel Roque

Respostas:

11

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

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

Tente alterar o hello da string à direita, e ele não deve mais ecoar it works. Tente substituir echo hellopor um comando de sua escolha. Se você deseja ignorar maiúsculas e minúsculas e nenhuma string contém uma quebra de linha, você pode usar grep:

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

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

A -iopção do grep diz para ignorar maiúsculas e minúsculas.
A -qopção diz para não emitir saída e sair após a primeira partida.
A -Fopção diz para tratar o argumento como uma string em vez de uma expressão regular.

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

BobDoolittle
fonte
Não entendo por que Gilles achou necessário alterar o código que eu contribuí. Ele não quebrou nada, mas funcionou muito bem. Você não precisa de aspas duplas neste exemplo - elas são importantes se a saída contiver espaços no entanto. E == funciona tão bem quanto = porque sh é realmente uma festança no Linux. O original Bourne Shell já se foi há muito tempo. Acho que nem o Solaris o envia mais. Embora desnecessário neste exemplo, concordo que aspas duplas são provavelmente uma prática recomendada, mas também é '==' na minha opinião, para manter a atribuição e a comparação claramente separadas.
BobDoolittle
Espere, para que se possa editar uma postagem? Eu não sabia disso.
Miguel Roque
Com reputação suficiente, sim. Espero que alguém com alta reputação pense duas vezes antes de fazer edições desnecessárias, principalmente para codificar neste fórum. unix.stackexchange.com/help/privileges
BobDoolittle
@BobDoolittle Pode ser que em certos casos isso faça diferença, mas não na sua configuração - é bom saber.
2
Observe que, na prática, não se trata apenas do shell Bourne. ==não é POSIX. shnão está bashem todos os sistemas baseados em Linux. ==não é suportado por ash(sobre o qual shse baseia pelo menos muitos dos BSDs e derivados do Debian), ou posh, e precisa ser citado em zsh. Não faz sentido dobrar o =. [é um comando para teste. Não há necessidade de desambiguar entre atribuição e comparação aqui. Isso é diferente em (( a == b ))vs (( a = b)). O uso ==de um script que começa com #! /bin/shestá errado. Se você assumir kshou bashsintaxe, atualize-o de #!acordo.
Stéphane Chazelas
49

É possível fazer a correspondência de substring sem distinção entre maiúsculas e minúsculas bashusando o operador regex =~se você definir a nocasematchopção 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
chave de aço
fonte
6
ri muito! pontos por conhecimento obscuro do shell.
BobDoolittle
2
Essa opção também afeta o operador de correspondência simples. [[ XYZ == xyz ]] && echo "match"=>match
itsadok 5/17/17
7

Para uma pesquisa de cadeia que diferencia maiúsculas de minúsculas do valor da variável needleno valor da variável haystack:

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

Para uma pesquisa de cadeias sem distinção entre maiúsculas e minúsculas, converta ambas 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 trcoreutils no GNU não suporta localidades multibyte (por exemplo, UTF-8). Para trabalhar com códigos de idioma multibyte, use o awk. Se você usar o awk, poderá fazer a comparação de cadeias 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 trBusyBox não suporta a sintaxe; você pode usar em seu lugar. O BusyBox não suporta localidades não ASCII.[:CLASS:]tr a-z A-Z

No bash (mas não sh), versão 4.0+, há uma sintaxe interna para conversão de maiúsculas e minúsculas e uma sintaxe mais simples para correspondência de cadeias.

if [[ "${haystack^^}" = *"${needle^^}"* ]]; then
  echo "present"
else
  echo "absent"
esac
Gilles 'SO- parar de ser mau'
fonte
Sei que isso tem alguns anos, mas tudo isso printf | trfaz minha cabeça girar. Sempre que possível, mantenha sua chamada de comandos no mínimo ... dada uma variável v, você pode realizar a mesma coisa usando v=$(tr '[:lower:]' '[:upper:]' <<<$v). Para aqueles que nunca viram isso antes, a <<<é essencialmente uma "variável aqui", como o uso de <<EOFé para um documento aqui. Não faça isso printfou a echomenos que você absolutamente precise fazê-lo.
Will
@ Will Isso funciona apenas em shells que possuem o <<<operador: ksh, bash, zsh, mas não sh simples. E está muito próximo de ser canalizado printfem termos de como é executado: há o mesmo número de chamadas para forke execve(supondo que printfesteja embutido, como é o caso dos shells mais comuns); uma diferença é que <<<cria um arquivo temporário em vez de usar um pipe. <<<É conveniente digitar, mas não uma melhoria de desempenho.
Gilles 'SO- stop be evil' (