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

162

Quiero poner en mayúscula solo el primer carácter de mi cadena con bash.

foo="bar";

//uppercase first character

echo $foo;

debe imprimir "Bar";

chovy
fuente
1
No es un duplicado exacto, pero muchas de las técnicas descritas en Convertir cadenas a minúsculas en el script de shell Bash también se pueden aplicar a este problema.
pjh

Respuestas:

148
foo="$(tr '[:lower:]' '[:upper:]' <<< ${foo:0:1})${foo:1}"
Michael Hoffman
fuente
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
Steve
fuente
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
Steve
fuente
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
Majid Laissi
fuente
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
Equin0x
fuente
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))}'
toske
fuente
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}"
Michał Górny
fuente
¿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:

zetaomegagon
fuente
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+)

Ole Lukøje
fuente
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

Thomas Webber
fuente
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
Shemeshey
fuente
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&/'
Hombre libre
fuente
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
Ivan
fuente
-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}

usuario123456
fuente
-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=
Roger
fuente
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