Comparação sem distinção entre maiúsculas e minúsculas de strings no shell script

129

O ==operador é usado para comparar duas strings no shell script. No entanto, quero comparar duas strings ignorando maiúsculas e minúsculas, como isso pode ser feito? Existe algum comando padrão para isso?

Sachin Chourasiya
fonte

Respostas:

72

se você tiver festança

str1="MATCH"
str2="match"
shopt -s nocasematch
case "$str1" in
 $str2 ) echo "match";;
 *) echo "no match";;
esac

caso contrário, você deve nos dizer qual shell você está usando.

alternativa, usando awk

str1="MATCH"
str2="match"
awk -vs1="$str1" -vs2="$str2" 'BEGIN {
  if ( tolower(s1) == tolower(s2) ){
    print "match"
  }
}'
ghostdog74
fonte
32
Para qualquer pessoa que compare cadeias de caracteres usando ifinstruções, a shoptabordagem exige que você use o formato de parênteses duplos em [[ ]]vez do [ ]formulário entre parênteses . Veja também: gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html
indiv
3
A pergunta indica que ==é usada para comparar duas cadeias, mas a resposta demonstra uma comparação sem distinção entre maiúsculas e minúsculas usando uma caseinstrução Reasseguradamente, a shoptsolução também permite o uso de maiúsculas e minúsculas de ==, =~e outros operadores de comparação de cadeia.
Taranaki
7
Provavelmente, é prudente executar shopt -u nocasematchapós a comparação, a fim de voltar ao padrão do bash.
Ohad Schneider
6
Melhor salvar e restaurar a nocasematchconfiguração. Agarre-o com, em SHELLNOCASEMATCH=`shopt -p nocasematch`seguida, altere-o shopt -s nocasematche, uma vez feito, restaure-o com #$SHELLNOCASEMATCH
Urhixidur
2
Melhor ainda:, SHELLNOCASEMATCH=$(shopt -p nocasematch; true)porque shopt -psairá com o código 1 se a opção não estiver configurada e isso pode causar o cancelamento do script se set -eestiver em vigor.
Estamos todos Monica
158

No Bash, você pode usar a expansão de parâmetros para modificar uma string para todas as letras maiúsculas / minúsculas:

var1=TesT
var2=tEst

echo ${var1,,} ${var2,,}
echo ${var1^^} ${var2^^}
alfaniner
fonte
14
Pelo menos uma resposta que não implica a opção de compra. Assim, você pode comparar o caso de duas cordas ignorando e, no mesmo teste, comparar outros dois com o caso. Obrigado
jehon
37
Isso é novo no Bash 4? Pelo menos no Bash 3.2.51 (usado no OS X 10.9), ele não funciona - a primeira echoinstrução resulta em:-bash: ${var1,,}: bad substitution
Felix Rabe
1
Tais implementações de comparação que não diferenciam maiúsculas de minúsculas são propensas a problemas de localização (como o problema do turco I). Não sei como shopt -s nocasematché implementado, mas geralmente essas soluções no "idioma" lidam com isso corretamente.
Ohad Schneider
5
@Ohad Schneider, deixe a preocupação turcos sobre problemas de localização turca, eu só preciso de uma maneira rápida e eficiente para string jogo e isso leva o bolo pela margem huuuuuge
Niken
1
usuários do macOS, atualize sua versão do Bash. O seu está desatualizado há mais de uma década neste ponto. itnext.io/upgrading-bash-on-macos-7138bd1066ba
Jason Carter
114

Todas essas respostas ignoram a maneira mais fácil e rápida de fazer isso (desde que você tenha o Bash 4):

if [ "${var1,,}" = "${var2,,}" ]; then
  echo ":)"
fi

Tudo o que você está fazendo lá é converter as duas strings em minúsculas e comparar os resultados.

Tumulto
fonte
6
Isso está disponível apenas no Bash 4 ou mais recente (por exemplo, não no Mac OS X 10.11)
d4Rk 11/11/16
8
@ d4Rk, e é por isso que a primeira frase da minha resposta diz "contanto que você tenha o Bash 4". Dito isto, o Bash 4 está fora há mais de sete anos no momento em que escrevi este comentário, e minha própria instalação do OS X o mantém há quase tanto tempo.
Motim
@ Motim desculpe, não percebi isso em primeiro lugar. Eu sei que você pode instalar o bash que quiser no OS X, mas o padrão é 3.2 e como meu script deve ser executado em diferentes Macs também, essa não é realmente uma opção para mim.
d4Rk
2
@ d4Rk é compreensível - se você realmente precisa garantir a portabilidade, sugiro seguir o padrão de shell POSIX, pois não há garantia de encontrar nenhuma versão do bash em alguns casos.
Motim
1
Era exatamente isso que eu estava procurando. Devem ser mais acima =)
Robin Winslow
39

Salve o estado de nocasematch (caso alguma outra função dependa de sua desativação):

local orig_nocasematch=$(shopt -p nocasematch)
shopt -s nocasematch
[[ "foo" == "Foo" ]] && echo "match" || echo "notmatch"
$orig_nocasematch

Nota: use apenas localse estiver dentro de uma função.

Gerry Hickman
fonte
4
Bom porque casedeclarações (incluindo as da resposta do ghostdog) sempre fazem minha pele arrepiar
SeldomNeedy
15

Uma maneira seria converter as duas strings para superior ou inferior:

test $(echo "string" | /bin/tr '[:upper:]' '[:lower:]') = $(echo "String" | /bin/tr '[:upper:]' '[:lower:]') && echo same || echo different

Outra maneira seria usar o grep:

echo "string" | grep -qi '^String$' && echo same || echo different
Randy Proctor
fonte
Eu usei o trmétodo em meus aplicativos com docker iz baseados em alpine (que fornece shvia busybox). Obrigado.
MXWest 30/08/19
7

Para o korn shell, eu uso o comando interno typeset (-l para letras minúsculas e -u para letras maiúsculas).

var=True
typeset -l var
if [[ $var == "true" ]]; then
    print "match"
fi
Ek C.
fonte
2
Isso é muito melhor em termos de desempenho do que iniciar o awk ou qualquer outro processo.
21413 Alex
1
No bash, declare -l ou -u pode ser usado para definir os atributos.
Bharat
5

Muito fácil se você fgrep fazer uma linha que não diferencia maiúsculas de minúsculas:

str1="MATCH"
str2="match"

if [[ $(fgrep -ix $str1 <<< $str2) ]]; then
    echo "case-insensitive match";
fi
Cooper F. Nelson
fonte
Seria melhor usar em seu if fgrep -qix -- "$str1" <<<"$str2"; thenlugar.
3

Aqui está a minha solução usando tr:

var1=match
var2=MATCH
var1=`echo $var1 | tr '[A-Z]' '[a-z]'`
var2=`echo $var2 | tr '[A-Z]' '[a-z]'`
if [ "$var1" = "$var2" ] ; then
  echo "MATCH"
fi
stones333
fonte
3

greppossui uma -iflag que significa que não diferencia maiúsculas de minúsculas, então peça para informar se var2 está em var1.

var1=match 
var2=MATCH 
if echo $var1 | grep -i "^${var2}$" > /dev/null ; then
    echo "MATCH"
fi
Larry
fonte
3
não funcionará se houver caracteres especiais regex em var2.
haridsv
3

Para zsha sintaxe é um pouco diferente, mas ainda menor do que a maioria das respostas aqui:

> str1='mAtCh'
> str2='MaTcH'
> [[ "$str1:u" = "$str2:u" ]] && echo 'Strings Match!'
Strings Match!
>

Isso converterá as duas strings em maiúsculas antes da comparação.


Outro método utiliza zsh's globbing flags, o que nos permite usar diretamente a correspondência que não diferencia maiúsculas de minúsculas usando o isinalizador glob:

setopt extendedglob
[[ $str1 = (#i)$str2 ]] && echo "Match success"
[[ $str1 = (#i)match ]] && echo "Match success"
smac89
fonte
1

shopt -s nocaseglob

ennuikiller
fonte
1

Me deparei com este ótimo blog / tutorial / o que quer que seja sobre como lidar com padrões que diferenciam maiúsculas de minúsculas . Os três métodos a seguir são explicados em detalhes com exemplos:

1. Converta padrão em minúscula usando o comando tr

opt=$( tr '[:upper:]' '[:lower:]' <<<"$1" )
case $opt in
        sql)
                echo "Running mysql backup using mysqldump tool..."
                ;;
        sync)
                echo "Running backup using rsync tool..."
                ;;
        tar)
                echo "Running tape backup using tar tool..."
                ;;
        *)
                echo "Other options"
                ;;
esac

2. Use regex com padrões de caso

opt=$1
case $opt in
        [Ss][Qq][Ll])
                echo "Running mysql backup using mysqldump tool..."
                ;;
        [Ss][Yy][Nn][Cc])
                echo "Running backup using rsync tool..."
                ;;
        [Tt][Aa][Rr])
                echo "Running tape backup using tar tool..."
                ;;
        *)
                echo "Other option"
                ;;
esac

3. Ative o nocasematch

opt=$1
shopt -s nocasematch
case $opt in
        sql)
                echo "Running mysql backup using mysqldump tool..."
                ;;
        sync)
                echo "Running backup using rsync tool..."
                ;;
        tar)
                echo "Running tape backup using tar tool..."
                ;;
        *)
                echo "Other option"
                ;;
esac

shopt -u nocasematch
Sherzad
fonte