Como converter uma string para minúsculas no Bash?

Respostas:

2182

Existem várias maneiras:

Padrão POSIX

tr

$ echo "$a" | tr '[:upper:]' '[:lower:]'
hi all

AWK

$ echo "$a" | awk '{print tolower($0)}'
hi all

Não POSIX

Você pode ter problemas de portabilidade com os seguintes exemplos:

Bash 4.0

$ echo "${a,,}"
hi all

sed

$ echo "$a" | sed -e 's/\(.*\)/\L\1/'
hi all
# this also works:
$ sed -e 's/\(.*\)/\L\1/' <<< "$a"
hi all

Perl

$ echo "$a" | perl -ne 'print lc'
hi all

Bater

lc(){
    case "$1" in
        [A-Z])
        n=$(printf "%d" "'$1")
        n=$((n+32))
        printf \\$(printf "%o" "$n")
        ;;
        *)
        printf "%s" "$1"
        ;;
    esac
}
word="I Love Bash"
for((i=0;i<${#word};i++))
do
    ch="${word:$i:1}"
    lc "$ch"
done

Nota: YMMV neste. Não funciona para mim (versão 4.2.46 e 4.0.33 do GNU bash (e o mesmo comportamento 2.05b.0 mas o nocasematch não está implementado)) mesmo com o uso shopt -u nocasematch;. Desativar esse nocasematch faz com que [["fooBaR" == "FOObar"]] corresponda a OK, mas por dentro, estranhamente, [bz] é incorretamente correspondido por [AZ]. Bash é confundido com o duplo negativo ("nocasematch desestabilizador")! :-)

ghostdog74
fonte
9
Estou faltando alguma coisa ou o seu último exemplo (no Bash) realmente faz algo completamente diferente? Ele funciona para "ABX", mas se você fizer word="Hi All"os outros exemplos, ele retornará ha, não hi all. Funciona apenas para as letras maiúsculas e pula as letras já em minúsculas.
Jangosteve # 1
26
Observe que apenas os exemplos tre awksão especificados no padrão POSIX.
Richard Hansen
178
tr '[:upper:]' '[:lower:]'usará o código do idioma atual para determinar equivalentes em maiúsculas / minúsculas, portanto, ele funcionará com códigos de idioma que usam letras com marcas diacríticas.
Richard Hansen
10
Como se obtém a saída para uma nova variável? Ou seja, eu quero que a string em minúsculas seja uma nova variável?
Adam Parkin
60
@Adam:b="$(echo $a | tr '[A-Z]' '[a-z]')"
Tino
435

No Bash 4:

Para minúsculas

$ string="A FEW WORDS"
$ echo "${string,}"
a FEW WORDS
$ echo "${string,,}"
a few words
$ echo "${string,,[AEIUO]}"
a FeW WoRDS

$ string="A Few Words"
$ declare -l string
$ string=$string; echo "$string"
a few words

Para maiúsculas

$ string="a few words"
$ echo "${string^}"
A few words
$ echo "${string^^}"
A FEW WORDS
$ echo "${string^^[aeiou]}"
A fEw wOrds

$ string="A Few Words"
$ declare -u string
$ string=$string; echo "$string"
A FEW WORDS

Alternar (não documentado, mas opcionalmente configurável em tempo de compilação)

$ string="A Few Words"
$ echo "${string~~}"
a fEW wORDS
$ string="A FEW WORDS"
$ echo "${string~}"
a FEW WORDS
$ string="a few words"
$ echo "${string~}"
A few words

Capitalizar (não documentado, mas opcionalmente configurável em tempo de compilação)

$ string="a few words"
$ declare -c string
$ string=$string
$ echo "$string"
A few words

Caso do título:

$ string="a few words"
$ string=($string)
$ string="${string[@]^}"
$ echo "$string"
A Few Words

$ declare -c string
$ string=(a few words)
$ echo "${string[@]}"
A Few Words

$ string="a FeW WOrdS"
$ string=${string,,}
$ string=${string~}
$ echo "$string"
A few words

Para desativar um declareatributo, use +. Por exemplo declare +c string,. Isso afeta as atribuições subseqüentes e não o valor atual.

As declareopções alteram o atributo da variável, mas não o conteúdo. As reatribuições nos meus exemplos atualizam o conteúdo para mostrar as alterações.

Editar:

Adicionado "alternar o primeiro caractere pela palavra" ( ${var~}), como sugerido por ghostdog74 .

Edit: Corrigido o comportamento do til para coincidir com o Bash 4.3.

Pausado até novo aviso.
fonte
5
Bastante bizzare, os operadores "^^" e ",," não funcionam com caracteres não ASCII, mas "~~" funciona ... Então string="łódź"; echo ${string~~}, retornará "ŁÓDŹ", mas echo ${string^^}retornará "łóDź". Mesmo em LC_ALL=pl_PL.utf-8. Isso está usando o bash 4.2.24.
Hubert Kario
2
@HubertKario: Isso é estranho. É o mesmo para mim no Bash 4.0.33 com a mesma string en_US.UTF-8. É um bug e eu relatei.
Pausado até novo aviso.
1
@HubertKario: Tente echo "$string" | tr '[:lower:]' '[:upper:]'. Provavelmente exibirá a mesma falha. Portanto, o problema não é, pelo menos em parte, o de Bash.
Pausado até novo aviso.
1
@DennisWilliamson: Sim, eu também notei isso (veja o comentário na resposta de Shuvalov). Eu diria apenas "esse material é apenas para ASCII", mas é o operador "~~" que funciona, por isso não é como se as tabelas de código e tradução ainda não estivessem lá ...
Hubert Kario
4
@HubertKario: O mantenedor do Bash reconheceu o erro e afirmou que ele será corrigido na próxima versão.
Pausado até novo aviso.
123
echo "Hi All" | tr "[:upper:]" "[:lower:]"
shuvalov
fonte
4
@ RichardHansen: trnão funciona para mim para caracteres que não são da ACII. Eu tenho o conjunto de localizações correto e os arquivos de localidade gerados. Tem alguma idéia do que eu poderia estar fazendo de errado?
Hubert Kario
FYI: Isso funcionou no Windows / Msys. Algumas das outras sugestões não o fizeram.
wasatchwizard
3
Por que é [:upper:]necessário?
mgutt
77

tr :

a="$(tr [A-Z] [a-z] <<< "$a")"

AWK :

{ print tolower($0) }

sed :

y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
Ignacio Vazquez-Abrams
fonte
2
O +1 a="$(tr [A-Z] [a-z] <<< "$a")"parece mais fácil para mim. Eu ainda sou um iniciante ...
Sandeepan Nath 02/02
2
Eu recomendo fortemente a sedsolução; Eu tenho trabalhado em um ambiente que por algum motivo não tem tr, mas eu ainda tenho que encontrar um sistema, sem sed, além de uma grande parte do tempo que eu quero fazer isso eu acabei de fazer outra coisa em sedqualquer maneira para cadeia de lata os comandos juntos em uma única instrução (longa).
Haravikk
2
As expressões entre colchetes devem ser citadas. Em tr [A-Z] [a-z] A, o shell pode executar a expansão do nome do arquivo se houver nomes de arquivos consistindo em uma única letra ou se o nullgob estiver definido. tr "[A-Z]" "[a-z]" Ase comportará corretamente.
Dennis
2
@CamiloMartin, é um sistema BusyBox em que estou tendo esse problema, especificamente Synology NASes, mas também o encontrei em alguns outros sistemas. Ultimamente, venho desenvolvendo muitos scripts de shell de plataforma cruzada e, com o requisito de que nada extra seja instalado, isso torna as coisas muito complicadas! No entanto, eu ainda tenho que encontrar um sistema semsed
Haravikk
2
Observe que tr [A-Z] [a-z]está incorreto em quase todos os locais. por exemplo, na en-USlocalidade, A-Zé realmente o intervalo AaBbCcDdEeFfGgHh...XxYyZ.
fuz 31/01
44

Eu sei que este é um post antigo, mas eu respondi para outro site, então pensei em publicá-lo aqui:

UPPER -> lower : use python:

b=`echo "print '$a'.lower()" | python`

Ou Ruby:

b=`echo "print '$a'.downcase" | ruby`

Ou Perl (provavelmente o meu favorito):

b=`perl -e "print lc('$a');"`

Ou PHP:

b=`php -r "print strtolower('$a');"`

Ou Awk:

b=`echo "$a" | awk '{ print tolower($1) }'`

Ou Sed:

b=`echo "$a" | sed 's/./\L&/g'`

Ou Bash 4:

b=${a,,}

Ou NodeJS, se você o tiver (e estiver um pouco louco ...):

b=`echo "console.log('$a'.toLowerCase());" | node`

Você também pode usar dd(mas eu não usaria!):

b=`echo "$a" | dd  conv=lcase 2> /dev/null`

inferior -> SUPERIOR :

use python:

b=`echo "print '$a'.upper()" | python`

Ou Ruby:

b=`echo "print '$a'.upcase" | ruby`

Ou Perl (provavelmente o meu favorito):

b=`perl -e "print uc('$a');"`

Ou PHP:

b=`php -r "print strtoupper('$a');"`

Ou Awk:

b=`echo "$a" | awk '{ print toupper($1) }'`

Ou Sed:

b=`echo "$a" | sed 's/./\U&/g'`

Ou Bash 4:

b=${a^^}

Ou NodeJS, se você o tiver (e estiver um pouco louco ...):

b=`echo "console.log('$a'.toUpperCase());" | node`

Você também pode usar dd(mas eu não usaria!):

b=`echo "$a" | dd  conv=ucase 2> /dev/null`

Além disso, quando você diz 'shell', estou assumindo que você quer dizer, bashmas se você pode usá- zshlo, é tão fácil quanto

b=$a:l

para minúsculas e

b=$a:u

para maiúsculas.

nettux
fonte
@ JESii ambos trabalham para mim superior -> inferior e inferior -> superior. Estou usando o sed 4.2.2 e o Bash 4.3.42 (1) no Debian Stretch de 64 bits.
Nettux
1
Oi, @ nettux443 ... Acabei de tentar a operação do bash novamente e ela ainda falha com a mensagem de erro "substituição incorreta". Eu estou no OSX usando o bash do homebrew: GNU bash, versão 4.3.42 (1) -release (x86_64-apple-darwin14.5.0)
JESii
5
Não use! Todos os exemplos que geram um script são extremamente frágeis; se o valor de acontiver uma aspas simples, você não apenas terá um comportamento defeituoso, mas um sério problema de segurança.
Tripleee
Eu gosto mais da solução sed, pois o sed é sempre onipresente.
Dudi Boy
Eu prefiro usar a solução dd. Por favor note que você precisa ser root para fazê-lo funcionar
inetphantom
29

No zsh:

echo $a:u

Conseguiu amar o zsh!

Scott Smedley
fonte
4
ou $ a: l para menor conversão caso
Scott Smedley
1
Adicione mais um caso:echo ${(C)a} #Upcase the first char only
biocyberman
18

Usando o GNU sed:

sed 's/.*/\L&/'

Exemplo:

$ foo="Some STRIng";
$ foo=$(echo "$foo" | sed 's/.*/\L&/')
$ echo "$foo"
some string
devnull
fonte
12

Pre Bash 4.0

Bash Abaixe a caixa de uma string e atribua à variável

VARIABLE=$(echo "$VARIABLE" | tr '[:upper:]' '[:lower:]') 

echo "$VARIABLE"
hawkeye126
fonte
5
Não há necessidade de echotubos: use$(tr '[:upper:]' '[:lower:]' <<<"$VARIABLE")
Tino
3
@Tino A string here também não é portátil para versões realmente antigas do Bash; Eu acredito que foi introduzido na v3.
Tripleee
1
@tripleee Você está certo, ele foi introduzido em bash-2.05b - no entanto, que é a festa mais velho que eu era capaz de encontrar em meus sistemas
Tino
11

Para um shell padrão (sem bashisms) usando apenas builtins:

uppers=ABCDEFGHIJKLMNOPQRSTUVWXYZ
lowers=abcdefghijklmnopqrstuvwxyz

lc(){ #usage: lc "SOME STRING" -> "some string"
    i=0
    while ([ $i -lt ${#1} ]) do
        CUR=${1:$i:1}
        case $uppers in
            *$CUR*)CUR=${uppers%$CUR*};OUTPUT="${OUTPUT}${lowers:${#CUR}:1}";;
            *)OUTPUT="${OUTPUT}$CUR";;
        esac
        i=$((i+1))
    done
    echo "${OUTPUT}"
}

E para maiúsculas:

uc(){ #usage: uc "some string" -> "SOME STRING"
    i=0
    while ([ $i -lt ${#1} ]) do
        CUR=${1:$i:1}
        case $lowers in
            *$CUR*)CUR=${lowers%$CUR*};OUTPUT="${OUTPUT}${uppers:${#CUR}:1}";;
            *)OUTPUT="${OUTPUT}$CUR";;
        esac
        i=$((i+1))
    done
    echo "${OUTPUT}"
}
technosaurus
fonte
Gostaria de saber se você não deixou algum basismo neste script, pois ele não é portável no FreeBSD sh: $ {1: $ ...}: Substituição ruim
Dereckson #
2
De fato; substrings com ${var:1:1}são um Bashism.
Tripleee
Essa abordagem tem métricas de desempenho muito ruins. Veja minha resposta para métricas.
DeJay Clayton
9

No bash 4, você pode usar o typeset

Exemplo:

A="HELLO WORLD"
typeset -l A=$A
c4f4t0r
fonte
7

Expressão regular

Gostaria de receber o crédito pelo comando que desejo compartilhar, mas a verdade é que eu o obtive para meu próprio uso em http://commandlinefu.com . Tem a vantagem de que, se você cdacessar um diretório dentro de sua própria pasta pessoal, ele alterará todos os arquivos e pastas para minúsculas recursivamente, use com cuidado. É uma correção de linha de comando brilhante e especialmente útil para as multidões de álbuns que você armazenou em sua unidade.

find . -depth -exec rename 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \;

Você pode especificar um diretório no lugar do ponto (.) Após a localização, que indica o diretório atual ou o caminho completo.

Espero que essa solução seja útil. A única coisa que esse comando não faz é substituir espaços por sublinhados - bem, talvez outra hora.

Derek Shaw
fonte
Isso não funcionou para mim por qualquer motivo, embora pareça bem. Eu fiz isso funcionar como uma alternativa: encontrar. -exec / bin / bash -c 'mv {} `tr [AZ] [az] <<< {}`' \;
precisa
Isso precisa prenamede perl: dpkg -S "$(readlink -e /usr/bin/rename)"perl: /usr/bin/prename
Tino
4

Muitas respostas usando programas externos, o que realmente não está sendo usado Bash.

Se você sabe que terá o Bash4 disponível, use realmente a ${VAR,,}notação (é fácil e legal). Para o Bash anterior a 4 (meu Mac ainda usa o Bash 3.2, por exemplo). Usei a versão corrigida da resposta de @ ghostdog74 para criar uma versão mais portátil.

Você pode ligar lowercase 'my STRING'e obter uma versão em minúscula. Eu li comentários sobre como definir o resultado como um var, mas isso não é realmente portátil Bash, pois não podemos retornar strings. Imprimir é a melhor solução. Fácil de capturar com algo parecido var="$(lowercase $str)".

Como isso funciona

A maneira como isso funciona é obtendo a representação inteira ASCII de cada caractere com printfe então adding 32se upper-to->lower, ou subtracting 32se lower-to->upper. Em seguida, use printfnovamente para converter o número novamente em um caractere. Desde 'A' -to-> 'a'temos uma diferença de 32 caracteres.

Usando printfpara explicar:

$ printf "%d\n" "'a"
97
$ printf "%d\n" "'A"
65

97 - 65 = 32

E esta é a versão de trabalho com exemplos.
Observe os comentários no código, pois eles explicam muitas coisas:

#!/bin/bash

# lowerupper.sh

# Prints the lowercase version of a char
lowercaseChar(){
    case "$1" in
        [A-Z])
            n=$(printf "%d" "'$1")
            n=$((n+32))
            printf \\$(printf "%o" "$n")
            ;;
        *)
            printf "%s" "$1"
            ;;
    esac
}

# Prints the lowercase version of a sequence of strings
lowercase() {
    word="$@"
    for((i=0;i<${#word};i++)); do
        ch="${word:$i:1}"
        lowercaseChar "$ch"
    done
}

# Prints the uppercase version of a char
uppercaseChar(){
    case "$1" in
        [a-z])
            n=$(printf "%d" "'$1")
            n=$((n-32))
            printf \\$(printf "%o" "$n")
            ;;
        *)
            printf "%s" "$1"
            ;;
    esac
}

# Prints the uppercase version of a sequence of strings
uppercase() {
    word="$@"
    for((i=0;i<${#word};i++)); do
        ch="${word:$i:1}"
        uppercaseChar "$ch"
    done
}

# The functions will not add a new line, so use echo or
# append it if you want a new line after printing

# Printing stuff directly
lowercase "I AM the Walrus!"$'\n'
uppercase "I AM the Walrus!"$'\n'

echo "----------"

# Printing a var
str="A StRing WITH mixed sTUFF!"
lowercase "$str"$'\n'
uppercase "$str"$'\n'

echo "----------"

# Not quoting the var should also work, 
# since we use "$@" inside the functions
lowercase $str$'\n'
uppercase $str$'\n'

echo "----------"

# Assigning to a var
myLowerVar="$(lowercase $str)"
myUpperVar="$(uppercase $str)"
echo "myLowerVar: $myLowerVar"
echo "myUpperVar: $myUpperVar"

echo "----------"

# You can even do stuff like
if [[ 'option 2' = "$(lowercase 'OPTION 2')" ]]; then
    echo "Fine! All the same!"
else
    echo "Ops! Not the same!"
fi

exit 0

E os resultados depois de executar isso:

$ ./lowerupper.sh 
i am the walrus!
I AM THE WALRUS!
----------
a string with mixed stuff!
A STRING WITH MIXED STUFF!
----------
a string with mixed stuff!
A STRING WITH MIXED STUFF!
----------
myLowerVar: a string with mixed stuff!
myUpperVar: A STRING WITH MIXED STUFF!
----------
Fine! All the same!

Isso deve funcionar apenas para caracteres ASCII .

Para mim, tudo bem, pois sei que só passarei caracteres ASCII para ele.
Estou usando isso para algumas opções de CLI que não diferenciam maiúsculas de minúsculas, por exemplo.

Gus Neves
fonte
4

A conversão de maiúsculas e minúsculas é feita apenas para alfabetos. Portanto, isso deve funcionar perfeitamente.

Estou focando na conversão de alfabetos entre az de maiúsculas para minúsculas. Quaisquer outros caracteres devem ser impressos apenas em stdout, pois são ...

Converte todo o texto no caminho / para / arquivo / nome do arquivo dentro do intervalo de az para AZ

Para converter letras minúsculas em maiúsculas

cat path/to/file/filename | tr 'a-z' 'A-Z'

Para converter de maiúsculas para minúsculas

cat path/to/file/filename | tr 'A-Z' 'a-z'

Por exemplo,

nome do arquivo:

my name is xyz

é convertido em:

MY NAME IS XYZ

Exemplo 2:

echo "my name is 123 karthik" | tr 'a-z' 'A-Z'
# Output:
# MY NAME IS 123 KARTHIK

Exemplo 3:

echo "my name is 123 &&^&& #@$#@%%& kAR2~thik" | tr 'a-z' 'A-Z'
# Output:
# MY NAME IS 123 &&^&& #@0@%%& KAR2~THIK
theBuzzyCoder
fonte
3

Se estiver usando v4, este é cozido-in . Caso contrário, aqui está uma solução simples e amplamente aplicável . Outras respostas (e comentários) sobre este tópico foram bastante úteis na criação do código abaixo.

# Like echo, but converts to lowercase
echolcase () {
    tr [:upper:] [:lower:] <<< "${*}"
}

# Takes one arg by reference (var name) and makes it lowercase
lcase () { 
    eval "${1}"=\'$(echo ${!1//\'/"'\''"} | tr [:upper:] [:lower:] )\'
}

Notas:

  • Fazendo: a="Hi All"e então: lcase afará a mesma coisa que:a=$( echolcase "Hi All" )
  • Na função lcase, usar em ${!1//\'/"'\''"}vez de ${!1}permite que isso funcione mesmo quando a string possui aspas.
Stephen M. Harris
fonte
3

Para versões do Bash anteriores à 4.0, essa versão deve ser mais rápida (pois não bifurca / executa nenhum comando):

function string.monolithic.tolower
{
   local __word=$1
   local __len=${#__word}
   local __char
   local __octal
   local __decimal
   local __result

   for (( i=0; i<__len; i++ ))
   do
      __char=${__word:$i:1}
      case "$__char" in
         [A-Z] )
            printf -v __decimal '%d' "'$__char"
            printf -v __octal '%03o' $(( $__decimal ^ 0x20 ))
            printf -v __char \\$__octal
            ;;
      esac
      __result+="$__char"
   done
   REPLY="$__result"
}

a resposta do technosaurus também tinha potencial, embora funcionasse corretamente para mim.

Orwellophile
fonte
Não é ruim! Para uma análise do desempenho dessa abordagem, consulte minha resposta para métricas.
DeJay Clayton
3

Apesar de quantos anos essa pergunta tem e semelhante à resposta do technosaurus . Foi difícil encontrar uma solução que fosse portátil na maioria das plataformas (que eu uso) e nas versões mais antigas do bash. Também fiquei frustrado com matrizes, funções e uso de impressões, ecos e arquivos temporários para recuperar variáveis ​​triviais. Até agora, isso funcionou muito bem para mim e pensei em compartilhar. Meus principais ambientes de teste são:

  1. Lançamento do GNU bash, versão 4.1.2 (1) (x86_64-redhat-linux-gnu)
  2. Lançamento do GNU bash, versão 3.2.57 (1) (sparc-sun-solaris2.10)
lcs="abcdefghijklmnopqrstuvwxyz"
ucs="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
input="Change Me To All Capitals"
for (( i=0; i<"${#input}"; i++ )) ; do :
    for (( j=0; j<"${#lcs}"; j++ )) ; do :
        if [[ "${input:$i:1}" == "${lcs:$j:1}" ]] ; then
            input="${input/${input:$i:1}/${ucs:$j:1}}" 
        fi
    done
done

Estilo C simples para loop para iterar pelas seqüências de caracteres. Para a linha abaixo, se você nunca viu nada assim antes, foi aqui que eu aprendi isso . Nesse caso, a linha verifica se o char $ {input: $ i: 1} (minúsculo) existe na entrada e, se houver, substitui-o pelo dado char $ {ucs: $ j: 1} (maiúsculo) e o armazena de volta à entrada.

input="${input/${input:$i:1}/${ucs:$j:1}}"
JaredTS486
fonte
Isso é extremamente ineficiente, repetindo 650 vezes no exemplo acima e demorando 35 segundos para executar 1000 invocações na minha máquina. Para uma alternativa que faça um loop apenas 11 vezes e leve menos de 5 segundos para executar 1000 invocações, veja minha resposta alternativa.
DeJay Clayton #
1
Obrigado, embora isso deva ser óbvio apenas olhando para ele. Talvez as falhas de página sejam do tamanho da entrada e do número de iterações que você está executando. No entanto, eu gosto da sua solução.
precisa saber é o seguinte
3

Essa é uma variação muito mais rápida da abordagem do JaredTS486 que usa recursos nativos do Bash (incluindo versões do Bash <4.0) para otimizar sua abordagem.

Cronometrei 1.000 iterações dessa abordagem para uma sequência pequena (25 caracteres) e uma sequência maior (445 caracteres), tanto para conversões em minúsculas quanto em maiúsculas. Como as sequências de teste são predominantemente em minúsculas, as conversões em minúsculas geralmente são mais rápidas que em maiúsculas.

Comparei minha abordagem com várias outras respostas nesta página que são compatíveis com o Bash 3.2. Minha abordagem é muito mais eficiente do que a maioria das abordagens documentadas aqui e é ainda mais rápida do que trem vários casos.

Aqui estão os resultados de temporização para 1.000 iterações de 25 caracteres:

Resultados de tempo para 1.000 iterações de 445 caracteres (consistindo no poema "The Robin" de Witter Bynner):

  • 2s para minha abordagem em minúsculas; 12s para maiúsculas
  • 4s para trminúsculas; 4s para maiúsculas
  • 20s para a abordagem de Orwellophile para minúsculas; 29s para maiúsculas
  • 75s para a abordagem de ghostdog74 em minúsculas; 669s para maiúsculas. É interessante notar o quão dramática é a diferença de desempenho entre um teste com correspondências predominantes e um teste com faltas predominantes
  • 467s para a abordagem do technosaurus em minúsculas; 449s para maiúsculas
  • 660s para a abordagem de JaredTS486 em minúsculas; 660s para maiúsculas. É interessante notar que essa abordagem gerou falhas contínuas de página (troca de memória) no Bash

Solução:

#!/bin/bash
set -e
set -u

declare LCS="abcdefghijklmnopqrstuvwxyz"
declare UCS="ABCDEFGHIJKLMNOPQRSTUVWXYZ"

function lcase()
{
  local TARGET="${1-}"
  local UCHAR=''
  local UOFFSET=''

  while [[ "${TARGET}" =~ ([A-Z]) ]]
  do
    UCHAR="${BASH_REMATCH[1]}"
    UOFFSET="${UCS%%${UCHAR}*}"
    TARGET="${TARGET//${UCHAR}/${LCS:${#UOFFSET}:1}}"
  done

  echo -n "${TARGET}"
}

function ucase()
{
  local TARGET="${1-}"
  local LCHAR=''
  local LOFFSET=''

  while [[ "${TARGET}" =~ ([a-z]) ]]
  do
    LCHAR="${BASH_REMATCH[1]}"
    LOFFSET="${LCS%%${LCHAR}*}"
    TARGET="${TARGET//${LCHAR}/${UCS:${#LOFFSET}:1}}"
  done

  echo -n "${TARGET}"
}

A abordagem é simples: enquanto a string de entrada tem letras maiúsculas restantes, localize a próxima e substitua todas as instâncias dessa letra por sua variante minúscula. Repita até que todas as letras maiúsculas sejam substituídas.

Algumas características de desempenho da minha solução:

  1. Usa apenas utilitários embutidos no shell, o que evita a sobrecarga de chamar utilitários binários externos em um novo processo
  2. Evita subcascas, que sofrem penalidades de desempenho
  3. Utiliza mecanismos de shell que são compilados e otimizados para desempenho, como substituição global de cadeias dentro de variáveis, ajuste de sufixos de variáveis ​​e pesquisa e correspondência de expressões regulares. Esses mecanismos são muito mais rápidos do que iterando manualmente através de strings
  4. Repete apenas o número de vezes que a contagem de caracteres correspondentes únicos deve ser convertida. Por exemplo, converter uma sequência que possui três caracteres maiúsculos diferentes em minúsculas requer apenas três iterações de loop. Para o alfabeto ASCII pré-configurado, o número máximo de iterações de loop é 26
  5. UCSe LCSpode ser aumentado com caracteres adicionais
Dejay Clayton
fonte
2

Para armazenar a sequência transformada em uma variável. A seguir trabalhou para mim - $SOURCE_NAMEpara$TARGET_NAME

TARGET_NAME="`echo $SOURCE_NAME | tr '[:upper:]' '[:lower:]'`"
nitinr708
fonte
1

Maneira simples

echo "Hi all" | awk '{ print tolower($0); }'
Atul23
fonte