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?


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 ]


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

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

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' (
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.