primer carácter en mayúscula en una variable con bash


Respuestas:


148
foo="$(tr '[:lower:]' '[:upper:]' <<< ${foo:0:1})${foo:1}"

2
A pesar de ser más complejo que la respuesta mejor calificada, esta realmente hace exactamente eso: 'primer carácter en mayúscula en una variable'. La respuesta mejor calificada no tiene ese resultado. ¿Parece que las respuestas simples se votan de mejor manera que las correctas?
Krzysztof Jabłoński

15
@ KrzysztofJabłoński: En realidad, la "respuesta mejor calificada" a continuación producirá los mismos resultados que esta respuesta en Bash 4. Esta respuesta tiene la sobrecarga de llamar a una subshell (otra shell), la sobrecarga de llamar a la utilidad 'tr' (otro proceso , no Bash), la sobrecarga de usar here-doc / string (creación de archivo temporal) y usa dos sustituciones en comparación con la respuesta mejor calificada. Si absolutamente debe escribir código heredado, considere usar una función en lugar de una subshell.
Steve

2
Esta respuesta asume que la entrada es todo en minúsculas. Esta variante no tiene supuestos: $ (tr '[: lower:]' '[: upper:]' <<< $ {foo: 0: 1}) $ (tr '[: upper:]' '[: lower: ] '<<< $ {foo: 1})
Itai Hanski

55
@ItaiHanski El OP no especificó qué debería pasar con los personajes restantes, solo el primero. Se supone que querían cambiar notQuiteCamela NotQuiteCamel. Su variante tiene el efecto secundario u obliga al resto a minúsculas, a costa de duplicar el número de subcapas y procesos tr.
Jesse Chisholm

3
@DanieleOrlando, cierto, pero esta pregunta no tiene otras etiquetas que no sean bash.
Charles Duffy

313

Una forma con bash (versión 4+):

foo=bar
echo "${foo^}"

huellas dactilares:

Bar

2
¿Hay algo opuesto a esto?
CMCDragonkai

44
@CMCDragonkai: para poner en minúscula la primera letra, use "${foo,}". Para minúsculas todas las letras, use "${foo,,}". Para poner en mayúscula todas las letras, use "${foo^^}".
Steve

1
Accidentalmente noté eso ${foo~}y ${foo~~}tengo el mismo efecto que ${foo^}y ${foo^^}. Pero nunca vi esa alternativa mencionada en ninguna parte.
mivk

55
Esto no parece funcionar en Mac. obteniendo el siguiente error:bad substitution
Toland Hon

1
@TolandHon: Como probablemente ya haya trabajado, necesitará actualizar a la versión 4.x, o probar otra solución si esa máquina no puede actualizarse por alguna razón.
Steve

29

Unidireccional con sed:

echo "$(echo "$foo" | sed 's/.*/\u&/')"

Huellas dactilares:

Bar

10
no funciona en MacOS10 Lion sed, suspiro, el \ u se expande hacia ti en lugar de ser un operador.
vwvan

2
@vwvan brew install coreutils gnu-sedy siga las instrucciones para usar los comandos sin el prefijo g. Por lo que vale, nunca quise ejecutar la versión OSX de estos comandos desde que obtuve las versiones GNU.
Dean el

@vwvan: Sí, lo siento, necesitarás GNU seden este caso
Steve

2
@Dean: FWIW, nunca quise ejecutar OSX :-)
Steve

55
Simplemente cámbielo a sed 's/./\U&/y funcionará en POSIX sed.
David Conrad

24
$ foo="bar";
$ foo=`echo ${foo:0:1} | tr  '[a-z]' '[A-Z]'`${foo:1}
$ echo $foo
Bar

14

Aquí está la forma de herramientas de texto "nativo":

#!/bin/bash

string="abcd"
first=`echo $string|cut -c1|tr [a-z] [A-Z]`
second=`echo $string|cut -c2-`
echo $first$second

finalmente algo que funciona con una variable y en Mac! ¡Gracias!
OZZIE

44
@DanieleOrlando, no es tan portátil como cabría esperar. tr [:lower:] [:upper:]es una mejor opción si necesita trabajar en idiomas / idiomas incorporando letras que no están en los rangos a-zo A-Z.
Charles Duffy

8

Usar solo awk

foo="uNcapItalizedstrIng"
echo $foo | awk '{print toupper(substr($0,0,1))tolower(substr($0,2))}'

resultado: Uncapitalizedstring
Alex Freshmann

4

También se puede hacer en bash puro con bash-3.2:

# First, get the first character.
fl=${foo:0:1}

# Safety check: it must be a letter :).
if [[ ${fl} == [a-z] ]]; then
    # Now, obtain its octal value using printf (builtin).
    ord=$(printf '%o' "'${fl}")

    # Fun fact: [a-z] maps onto 0141..0172. [A-Z] is 0101..0132.
    # We can use decimal '- 40' to get the expected result!
    ord=$(( ord - 40 ))

    # Finally, map the new value back to a character.
    fl=$(printf '%b' '\'${ord})
fi

echo "${fl}${foo:1}"

¿Cómo definir foo? Lo intenté foo = $1pero solo consigo-bash: foo: command not found
OZZIE

1
@OZZIE, no hay espacios alrededor de las =asignaciones. Esto es algo que shellcheck.net encontrará para usted programáticamente.
Charles Duffy

Siempre olvido eso de los scripts de shell ... solo lenguaje donde un espacio (antes / después) importa ... suspiro (python es al menos 4 si no recuerdo
mal

@OZZIE, tiene que importar, porque si no importara, no podría pasar =como argumento a un programa (¿cómo se supone que debe saber si se someprogram =está ejecutando someprogramo asignando a una variable llamada someprogram?)
Charles Duffy

3

Esto también funciona ...

FooBar=baz

echo ${FooBar^^${FooBar:0:1}}

=> Baz
FooBar=baz

echo ${FooBar^^${FooBar:1:1}}

=> bAz
FooBar=baz

echo ${FooBar^^${FooBar:2:2}}

=> baZ

Y así.

Fuentes:

Inroducciones / Tutoriales:


3

Para capitalizar solo la primera palabra:

foo='one two three'
foo="${foo^}"
echo $foo

O ne dos tres


Para capitalizar cada palabra en la variable:

foo="one two three"
foo=( $foo ) # without quotes
foo="${foo[@]^}"
echo $foo

O ne T wo T tres


(funciona en bash 4+)


foo='one two three'; foo=$(for i in $foo; do echo -n "${i^} "; done) Resolución más corta para cada palabra. foo Ahora es "One Two Three"
vr286

¿Cómo puedo poner en mayúscula las primeras 3 o 4 letras en mayúscula? ¿Como pqrs-123-v1 a PQRS-123-v1 ? O puede decir, todas las letras antes del primer guión ...
Vicky Dev hace

2

Solución alternativa y limpia para Linux y OSX, también se puede usar con variables bash

python -c "print(\"abc\".capitalize())"

devuelve Abc


0

Este me funcionó:

Buscar todos los archivos * php en el directorio actual y reemplazar el primer carácter de cada nombre de archivo con mayúscula:

Por ejemplo: test.php => Test.php

for f in *php ; do mv "$f" "$(\sed 's/.*/\u&/' <<< "$f")" ; done

44
La pregunta original era una cadena y no hacía referencia al cambio de nombre de los archivos.
AndySavage

0

solo por diversión aquí estás:

foo="bar";    

echo $foo | awk '{$1=toupper(substr($1,0,1))substr($1,2)}1'
# or
echo ${foo^}
# or
echo $foo | head -c 1 | tr [a-z] [A-Z]; echo $foo | tail -c +2
# or
echo ${foo:1} | sed -e 's/^./\B&/'

0

No es exactamente lo que pedí pero es bastante útil

declare -u foo #When the variable is assigned a value, all lower-case characters are converted to upper-case.

foo=bar
echo $foo
BAR

Y lo contrario

declare -l foo #When the variable is assigned a value, all upper-case characters are converted to lower-case.

foo=BAR
echo $foo
bar

-1
first-letter-to-lower () {
        str="" 
        space=" " 
        for i in $@
        do
                if [ -z $(echo $i | grep "the\|of\|with" ) ]
                then
                        str=$str"$(echo ${i:0:1} | tr  '[A-Z]' '[a-z]')${i:1}$space" 
                else
                        str=$str${i}$space 
                fi
        done
        echo $str
}
first-letter-to-upper-xc () {
        v-first-letter-to-upper | xclip -selection clipboard
}
first-letter-to-upper () {
        str="" 
        space=" " 
        for i in $@
        do
                if [ -z $(echo $i | grep "the\|of\|with" ) ]
                then
                        str=$str"$(echo ${i:0:1} | tr  '[a-z]' '[A-Z]')${i:1}$space" 
                else
                        str=$str${i}$space 
                fi
        done
        echo $str
}

first-letter-to-lower-xc () {v-first-letter-to-lower | xclip -selection portapapeles}


-7

¿Qué sucede si el primer carácter no es una letra (sino una tabulación, un espacio y una comilla doble escapada)? Será mejor que prueba que hasta que encontramos una carta! Entonces:

S='  \"ó foo bar\"'
N=0
until [[ ${S:$N:1} =~ [[:alpha:]] ]]; do N=$[$N+1]; done
#F=`echo ${S:$N:1} | tr [:lower:] [:upper:]`
#F=`echo ${S:$N:1} | sed -E -e 's/./\u&/'` #other option
F=`echo ${S:$N:1}
F=`echo ${F} #pure Bash solution to "upper"
echo "$F"${S:(($N+1))} #without garbage
echo '='${S:0:(($N))}"$F"${S:(($N+1))}'=' #garbage preserved

Foo bar
= \"Foo bar=

66
¡Por favor escriba un código más limpio! te faltan citas por todas partes. Estás utilizando una sintaxis obsoleta (backticks); estás usando una sintaxis anticuada ( $[...]). Estás usando muchos paréntesis inútiles. Estás asumiendo que la cadena consiste en caracteres del alfabeto latino (¿qué tal letras acentuadas o letras en otros alfabetos?). ¡Tienes mucho trabajo para hacer que este fragmento sea utilizable! (y dado que está utilizando expresiones regulares, también podría usar la expresión regular para encontrar la primera letra, en lugar de un bucle).
gniourf_gniourf

66
Creo que estas equivocado. Es el comentario obligatorio que acompaña al voto negativo, explicando todos los patrones y conceptos erróneos incorrectos de la respuesta. Por favor, aprenda de sus errores (y antes de eso, trate de entenderlos) en lugar de ser terco. Ser un buen compañero también es incompatible con la difusión de malas prácticas.
gniourf_gniourf

1
O, si usa Bash ≥4, no necesita tr:if [[ $S =~ ^([^[:alpha:]]*)([[:alpha:]].*) ]]; then out=${BASH_REMATCH[1]}${BASH_REMATCH[2]^}; else out=$S; fi; printf '%s\n' "$out"
gniourf_gniourf

55
Este código todavía está muy roto. Todavía usa backticks en lugar de la sintaxis de sustitución moderna; todavía tiene citas inigualables; todavía le faltan citas en lugares donde sí importan ; Etc. Intente poner algunos caracteres de globo en espacios en blanco en sus datos de prueba, si no cree que esas comillas faltantes marcan la diferencia, y solucione los problemas que shellcheck.net encuentra hasta que este código salga limpio.
Charles Duffy

2
En cuanto al idioma que citó en unix.stackexchange.com/questions/68694/… , lo que echa de menos es que echo $fooes un ejemplo de una situación en la que el analizador espera una lista de palabras ; así que en tu echo ${F}, el contenido de Fse divide en cadenas y se expande globalmente. Eso es igualmente cierto para el echo ${S:$N:1}ejemplo y todo lo demás. Ver BashPitfalls # 14 .
Charles Duffy
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.