¿Cómo convertir una cadena a minúsculas en Bash?

¿Hay alguna forma de convertir una cadena en una cadena de minúsculas?

Por ejemplo, si tengo:

a="Hi all" 

Quiero convertirlo a:

 "hi all" 

Las son varias maneras:

tr

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

AWK

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

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 

Intento

 lc(){ case "$1" in [AZ]) 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 

En Bash 4:

A 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 

A mayú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 (no documentado, pero opcionalmente configurable en tiempo de comstackción)

 $ 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 (no documentado, pero opcionalmente configurable en tiempo de comstackción)

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

Titulo del caso:

 $ 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 desactivar un atributo de declare , use + . Por ejemplo, declare +c string . Esto afecta asignaciones posteriores y no el valor actual.

Las opciones de declare cambian el atributo de la variable, pero no el contenido. Las reasignaciones en mis ejemplos actualizan los contenidos para mostrar los cambios.

Editar:

Se agregó “alternar el primer caracter por palabra” ( ${var~} ) como lo sugiere ghostdog74 .

Editar: corregido el comportamiento de tilde para que coincida con Bash 4.3.

 echo "Hi All" | tr "[:upper:]" "[:lower:]" 

tr :

 a="$(tr [AZ] [az] <<< "$a")" 

AWK :

 { print tolower($0) } 

sed :

 y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ 

Sé que esta es una publicación antigua pero hice esta respuesta para otro sitio, así que pensé en publicarla aquí:

SUPERIOR -> inferior : use python:

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

O Ruby:

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

O Perl (probablemente mi favorito):

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

O PHP:

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

O Awk:

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

O Sed:

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

O Bash 4:

 b=${a,,} 

O NodeJS si lo tienes (y estás un poco loco …):

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

También podría usar dd (¡pero yo no lo haría!):

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

inferior -> SUPERIOR :

usar python:

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

O Ruby:

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

O Perl (probablemente mi favorito):

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

O PHP:

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

O Awk:

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

O Sed:

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

O Bash 4:

 b=${a^^} 

O NodeJS si lo tienes (y estás un poco loco …):

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

También podría usar dd (¡pero yo no lo haría!):

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

Además, cuando dices ‘shell’ supongo que quieres decir bash pero si puedes usar zsh es tan fácil como

 b=$a:l 

para minúsculas y

 b=$a:u 

para mayúsculas

En zsh:

 echo $a:u 

Tengo que amar a zsh!

Usando GNU sed :

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

Ejemplo:

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

Para un shell estándar (sin bashisms) usando solo 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}" } 

Y para mayú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}" } 

Pre Bash 4.0

Bash Baje la caja de una cuerda y asigne a la variable

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

Expresión regular

Me gustaría tomar el crédito por el comando que deseo compartir, pero la verdad es que lo obtuve para mi propio uso en http://commandlinefu.com . Tiene la ventaja de que si realiza un cd a cualquier directorio dentro de su propia carpeta de inicio, cambiará todos los archivos y carpetas a minúsculas recursivamente, por favor, use con precaución. Es una corrección de línea de comandos shiny y especialmente útil para esas multitudes de álbumes que ha almacenado en su disco.

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

Puede especificar un directorio en lugar del punto (.) Después del hallazgo que denota el directorio actual o la ruta completa.

Espero que esta solución resulte útil. Lo único que este comando no hace es reemplazar espacios con guiones bajos, oh bien en otro momento.

En bash 4 puedes usar typeset

Ejemplo:

 A="HELLO WORLD" typeset -l A=$A 

Puedes intentar esto

 s="Hello World!" echo $s # Hello World! a=${s,,} echo $a # hello world! b=${s^^} echo $b # HELLO WORLD! 

enter image description here

ref: http://wiki.workassis.com/shell-script-convert-text-to-lowercase-and-uppercase/

Si usa v4, esto está cocido al horno . Si no, aquí hay una solución simple y ampliamente aplicable . Otras respuestas (y comentarios) en este hilo fueron bastante útiles para crear el código a continuación.

 # 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:

  • Hacer: a="Hi All" y luego: lcase a hará lo mismo que: a=$( echolcase "Hi All" )
  • En la función lcase, usar ${!1//\'/"'\''"} lugar de ${!1} permite que esto funcione incluso cuando la cadena tiene comillas.

Para las versiones de Bash anteriores a la 4.0, esta versión debe ser la más rápida (ya que no ejecuta / ejecuta ningún 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 [AZ] ) printf -v __decimal '%d' "'$__char" printf -v __octal '%03o' $(( $__decimal ^ 0x20 )) printf -v __char \\$__octal ;; esac __result+="$__char" done REPLY="$__result" } 

La respuesta del tecnosaurio también tenía potencial, aunque funcionaba bien para mí.

A pesar de la antigüedad de esta pregunta y similar a esta respuesta de Technosaurus . Me costó encontrar una solución que fuera portátil en la mayoría de las plataformas (que uso), así como versiones anteriores de bash. También me he sentido frustrado con las matrices, las funciones y el uso de impresiones, ecos y archivos temporales para recuperar variables triviales. Esto funciona muy bien para mí hasta ahora, pensé que lo compartiría. Mis principales entornos de prueba son:

  1. GNU bash, versión 4.1.2 (1) -lanzamiento (x86_64-redhat-linux-gnu)
  2. GNU bash, versión 3.2.57 (1) – liberación (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 simple para que el ciclo itere a través de las cadenas. Para la línea a continuación si no has visto algo así antes, aquí es donde aprendí esto . En este caso, la línea verifica si el carácter $ {input: $ i: 1} (minúscula) existe en la entrada y si es así lo reemplaza con el carácter dado $ {ucs: $ j: 1} (mayúscula) y lo almacena volver a la entrada.

 input="${input/${input:$i:1}/${ucs:$j:1}}" 

Muchas respuestas usan progtwigs externos, que realmente no usan Bash .

Si sabe que tendrá Bash4 disponible, debería simplemente usar la notación ${VAR,,} (es fácil y genial). Para Bash antes de 4 (Mi Mac todavía usa Bash 3.2 por ejemplo). Utilicé la versión corregida de la respuesta de @ ghostdog74 para crear una versión más portátil.

Uno puede llamar lowercase 'my STRING' y obtener una versión en minúscula. Leí comentarios sobre cómo configurar el resultado en una var, pero eso no es realmente portable en Bash , ya que no podemos devolver cadenas. Imprimirlo es la mejor solución. Fácil de capturar con algo como var="$(lowercase $str)" .

Cómo funciona esto

La forma en que esto funciona es obteniendo la representación en enteros ASCII de cada char con printf y luego adding 32 si es upper-to->lower , o subtracting 32 si es lower-to->upper . A continuación, use printf nuevamente para convertir el número de nuevo en un char. De 'A' -to-> 'a' tenemos una diferencia de 32 caracteres.

Usando printf para explicar:

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

97 - 65 = 32

Y esta es la versión de trabajo con ejemplos.
Tenga en cuenta los comentarios en el código, ya que explican muchas cosas:

 #!/bin/bash # lowerupper.sh # Prints the lowercase version of a char lowercaseChar(){ case "$1" in [AZ]) 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 [az]) 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 

Y los resultados después de ejecutar esto:

 $ ./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! 

Sin embargo, esto solo debería funcionar para los caracteres ASCII .

Para mí está bien, ya que sé que solo le pasaré caracteres ASCII.
Estoy usando esto para algunas opciones de CLI que no distinguen entre mayúsculas y minúsculas, por ejemplo.

La conversión de mayúsculas y minúsculas está hecha solo para alfabetos. Entonces, esto debería funcionar limpiamente.

Me estoy enfocando en convertir alfabetos entre az de mayúscula a minúscula. Cualquier otro carácter debería simplemente imprimirse en stdout como es …

Convierte todo el texto en ruta / a / archivo / nombre de archivo dentro del rango az a AZ

Para la conversión de minúsculas a mayúsculas

 cat path/to/file/filename | tr 'az' 'AZ' 

Para convertir de mayúsculas a minúsculas

 cat path/to/file/filename | tr 'AZ' 'az' 

Por ejemplo,

nombre del archivo:

 my name is xyz 

se convierte a:

 MY NAME IS XYZ 

Ejemplo 2:

 echo "my name is 123 karthik" | tr 'az' 'AZ' # Output: # MY NAME IS 123 KARTHIK 

Ejemplo 3:

 echo "my name is 123 &&^&& #@$#@%%& kAR2~thik" | tr 'az' 'AZ' # Output: # MY NAME IS 123 &&^&& #@0@%%& KAR2~THIK 

Para almacenar la cadena transformada en una variable. Lo siguiente funcionó para mí: $SOURCE_NAME a $TARGET_NAME

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

Esta es una variación mucho más rápida del enfoque de JaredTS486 que usa capacidades nativas de Bash (incluidas las versiones de Bash <4.0) para optimizar su enfoque.

He progtwigdo 1,000 iteraciones de este enfoque para una cadena pequeña (25 caracteres) y una cadena más grande (445 caracteres), tanto para conversiones en minúscula como en mayúscula. Dado que las cadenas de prueba son predominantemente minúsculas, las conversiones a minúsculas son generalmente más rápidas que a mayúsculas.

He comparado mi enfoque con varias otras respuestas en esta página que son compatibles con Bash 3.2. Mi enfoque es mucho más eficiente que la mayoría de los enfoques documentados aquí, y es incluso más rápido que tr en varios casos.

Aquí están los resultados de tiempo para 1,000 iteraciones de 25 caracteres:

  • 0.46s para mi aproximación a minúsculas; 0.96s para mayúsculas
  • 1.16s para el enfoque de Orwellophile a minúsculas; 1.59s para mayúsculas
  • 3.67s para tr a minúsculas; 3.81s para mayúsculas
  • 11.12s para el acercamiento de ghostdog74 a minúsculas; 31.41s para mayúsculas
  • 26.25s para el enfoque de technosaurus a minúsculas; 26.21s para mayúsculas
  • 25.06s para el enfoque de JaredTS486 en minúsculas; 27.04s para mayúsculas

Resultados de tiempo para 1,000 iteraciones de 445 caracteres (que consta del poema “The Robin” de Witter Bynner):

  • 2s para mi aproximación a minúsculas; 12s para mayúsculas
  • 4s para tr a minúsculas; 4s para mayúsculas
  • 20s para el enfoque de Orwellophile a minúsculas; 29s para mayúsculas
  • 75s para el acercamiento de ghostdog74 a minúsculas; 669s para mayúsculas. Es interesante notar cuán dramática es la diferencia de rendimiento entre una prueba con partidas predominantes versus una prueba con fallas predominantes
  • 467s para el enfoque de technosaurus a minúsculas; 449s para mayúsculas
  • 660s para el enfoque de JaredTS486 en minúsculas; 660 s para mayúsculas. Es interesante observar que este enfoque generó fallas de página continuas (intercambio de memoria) en Bash

Solución:

 #!/bin/bash set -e set -u declare LCS="abcdefghijklmnopqrstuvwxyz" declare UCS="ABCDEFGHIJKLMNOPQRSTUVWXYZ" function lcase() { local TARGET="${1-}" local UCHAR='' local UOFFSET='' while [[ "${TARGET}" =~ ([AZ]) ]] 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}" =~ ([az]) ]] do LCHAR="${BASH_REMATCH[1]}" LOFFSET="${LCS%%${LCHAR}*}" TARGET="${TARGET//${LCHAR}/${UCS:${#LOFFSET}:1}}" done echo -n "${TARGET}" } 

El enfoque es simple: mientras que la cadena de entrada tiene letras mayúsculas restantes presentes, encuentre la siguiente y reemplace todas las instancias de esa letra con su variante en minúscula. Repita hasta que todas las letras mayúsculas sean reemplazadas.

Algunas características de rendimiento de mi solución:

  1. Utiliza solo utilidades incorporadas de shell, lo que evita la sobrecarga de invocar utilidades binarias externas en un nuevo proceso
  2. Evita subcapas, que incurren en penalizaciones de rendimiento
  3. Utiliza mecanismos de shell que se comstackn y optimizan para el rendimiento, como el reemplazo de cadenas globales dentro de las variables, el recorte de sufijos variables y la búsqueda y coincidencia de expresiones regulares. Estos mecanismos son mucho más rápidos que iterar manualmente a través de cadenas
  4. Enlaza solo el número de veces requerido por el recuento de caracteres coincidentes únicos para convertir. Por ejemplo, convertir una cadena que tiene tres caracteres en mayúsculas diferentes en minúsculas requiere solo 3 iteraciones de bucle. Para el alfabeto ASCII preconfigurado, el número máximo de iteraciones de bucle es 26
  5. UCS y LCS se pueden boost con caracteres adicionales