premier caractère majuscule dans une variable avec bash

162

Je veux mettre en majuscule juste le premier caractère de ma chaîne avec bash.

foo="bar";

//uppercase first character

echo $foo;

devrait afficher "Bar";

chovy
la source
1
Ce n'est pas un doublon exact, mais de nombreuses techniques décrites dans Conversion de chaîne en minuscules dans les scripts shell Bash peuvent également être appliquées à ce problème.
pjh

Réponses:

148
foo="$(tr '[:lower:]' '[:upper:]' <<< ${foo:0:1})${foo:1}"
Michael Hoffman
la source
2
Bien qu'elle soit plus complexe que la réponse la mieux notée, celle-ci fait exactement cela: «premier caractère majuscule dans une variable». La réponse la mieux notée n'a pas ces résultats. On dirait que les réponses simples sont mieux votées que les bonnes?
Krzysztof Jabłoński
15
@ KrzysztofJabłoński: En fait, la "réponse la mieux notée" ci-dessous produira les mêmes résultats que cette réponse sous Bash 4. Cette réponse a la surcharge d'appeler un sous-shell (un autre shell), la surcharge d'appeler l'utilitaire 'tr' (un autre processus , pas Bash), la surcharge de l'utilisation d'un here-doc / string (création de fichier temporaire) et il utilise deux substitutions par rapport à la réponse la mieux notée. Si vous devez absolument écrire du code hérité, envisagez d'utiliser une fonction au lieu d'un sous-shell.
Steve
2
Cette réponse suppose que l'entrée est entièrement en minuscules. Cette variante n'a pas d'hypothèses: $ (tr '[: lower:]' '[: upper:]' <<< $ {foo: 0: 1}) $ (tr '[: upper:]' '[: lower: ] '<<< $ {foo: 1})
Itai Hanski
5
@ItaiHanski L'OP n'a pas précisé ce qui devrait arriver aux caractères restants, seulement le premier. Supposé qu'ils voulaient changer notQuiteCamelen NotQuiteCamel. Votre variante a pour effet secondaire de forcer le reste en minuscules - au prix de doubler le nombre de sous-coquilles et de processus tr.
Jesse Chisholm
3
@DanieleOrlando, c'est vrai, mais cette question n'a pas de balises autres que bash.
Charles Duffy
314

Aller simple avec bash (version 4+):

foo=bar
echo "${foo^}"

imprime:

Bar
Steve
la source
2
Y a-t-il un contraire à cela?
CMCDragonkai
44
@CMCDragonkai: Pour mettre en minuscule la première lettre, utilisez "${foo,}". Pour mettre toutes les lettres en minuscules, utilisez "${foo,,}". Pour mettre toutes les lettres en majuscules, utilisez "${foo^^}".
Steve
1
J'ai accidentellement remarqué cela ${foo~}et ${foo~~}j'ai le même effet que ${foo^}et ${foo^^}. Mais je n'ai jamais vu cette alternative mentionnée nulle part.
mivk le
5
cela ne semble pas fonctionner sur les Mac. obtenir l'erreur suivante:bad substitution
Toland Hon
1
@TolandHon: Comme vous l'avez probablement déjà fait, vous devrez passer à la version 4.x, ou essayer une autre solution si cette machine ne peut pas être mise à niveau pour une raison quelconque.
Steve
29

Aller simple avec sed:

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

Impressions:

Bar
Steve
la source
10
ne fonctionne pas sur MacOS10 Lion sed, soupir, le \ u se développe en u au lieu d'être un opérateur.
vwvan
2
@vwvan brew install coreutils gnu-sedet suivez les instructions pour utiliser les commandes sans le préfixe g. Pour ce que ça vaut, je n'ai jamais voulu exécuter la version OSX de ces commandes depuis l'obtention des versions GNU.
Dean
@vwvan: Oui, désolé, vous aurez besoin de GNU seddans ce cas
Steve
2
@Dean: FWIW, je n'ai jamais voulu exécuter OSX :-)
Steve
5
Changez-le simplement en sed 's/./\U&/et cela fonctionnera sur POSIX sed.
David Conrad
24
$ foo="bar";
$ foo=`echo ${foo:0:1} | tr  '[a-z]' '[A-Z]'`${foo:1}
$ echo $foo
Bar
Majid Laissi
la source
14

Voici la méthode des outils de texte "natifs":

#!/bin/bash

string="abcd"
first=`echo $string|cut -c1|tr [a-z] [A-Z]`
second=`echo $string|cut -c2-`
echo $first$second
Equin0x
la source
enfin quelque chose qui fonctionne avec une variable et sur Mac! Je vous remercie!
OZZIE
4
@DanieleOrlando, pas aussi portable qu'on pourrait l'espérer. tr [:lower:] [:upper:]est un meilleur choix s'il doit fonctionner dans une langue / des paramètres régionaux incorporant des lettres qui ne sont pas dans les plages a-zou A-Z.
Charles Duffy
8

Utiliser awk uniquement

foo="uNcapItalizedstrIng"
echo $foo | awk '{print toupper(substr($0,0,1))tolower(substr($0,2))}'
toske
la source
résultat: Uncapitalizedstring
Alex Freshmann
4

Cela peut également être fait en pure bash avec 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
la source
comment définir foo? J'ai essayé foo = $1mais je ne reçois que-bash: foo: command not found
OZZIE
1
@OZZIE, pas d'espace autour des =affectations. C'est quelque chose que shellcheck.net trouvera pour vous par programme.
Charles Duffy
J'oublie toujours ça à propos des scripts shell ... seul langage où un espace (avant / après) compte ... soupir (python vaut au moins 4 si je me souviens bien)
OZZIE
@OZZIE, ça doit avoir de l'importance, car si cela n'avait pas d'importance, vous ne pourriez pas passer =en argument à un programme (comment est-il censé savoir s'il someprogram =est en cours d'exécution someprogram, ou qu'il est assigné à une variable nommée someprogram?)
Charles Duffy
3

Cela fonctionne aussi ...

FooBar=baz

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

=> Baz
FooBar=baz

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

=> bAz
FooBar=baz

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

=> baZ

Etc.

Sources:

Inroductions / Tutoriels:

zêtaomégagon
la source
3

Pour mettre en majuscule uniquement le premier mot:

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

O ne deux trois


Pour mettre en majuscule chaque mot de la variable:

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

O ne T wo T ROIS


(fonctionne en bash 4+)

Ole Lukøje
la source
foo='one two three'; foo=$(for i in $foo; do echo -n "${i^} "; done) Résolution plus courte pour chaque mot. foo Now est "One Two Three"
vr286
Comment puis-je mettre les 3 ou 4 premières lettres en majuscules? Comme pqrs-123-v1 à PQRS-123-v1 ? Ou vous pouvez dire, toutes les lettres avant le premier trait d'union ...
Vicky Dev
2

Solution alternative et propre pour Linux et OSX, elle peut également être utilisée avec des variables bash

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

renvoie Abc

Thomas Webber
la source
0

Celui-ci a fonctionné pour moi:

Recherche de tous les fichiers * php dans le répertoire courant, et remplacez le premier caractère de chaque nom de fichier par une majuscule:

par exemple: test.php => Test.php

for f in *php ; do mv "$f" "$(\sed 's/.*/\u&/' <<< "$f")" ; done
Shemeshey
la source
4
La question d'origine était une chaîne et ne faisait aucune référence au changement de nom des fichiers.
AndySavage
0

juste pour le plaisir vous voilà:

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&/'
Homme libre
la source
0

Pas exactement ce qui a été demandé mais assez utile

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

foo=bar
echo $foo
BAR

Et le contraire

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
la source
-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 | presse-papiers de sélection xclip}

user123456
la source
-7

Que faire si le premier caractère n'est pas une lettre (mais une tabulation, un espace et un guillemet double échappé)? Nous ferions mieux de le tester jusqu'à ce que nous trouvions une lettre! Alors:

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
la source
6
Veuillez écrire un code plus propre! il vous manque des citations partout. Vous utilisez une syntaxe obsolète (backticks); vous utilisez une syntaxe désuète ( $[...]). Vous utilisez beaucoup de parenthèses inutiles. Vous supposez que la chaîne se compose de caractères de l'alphabet latin (qu'en est-il des lettres accentuées ou des lettres d'autres alphabets?). Vous avez beaucoup de travail pour rendre cet extrait utilisable! (et puisque vous utilisez regex, vous pouvez aussi bien utiliser l'expression régulière pour trouver la première lettre, au lieu d'une boucle).
gniourf_gniourf
6
Je crois que vous avez tort. C'est le commentaire obligatoire qui accompagne le vote défavorable, expliquant tous les mauvais modèles et les idées fausses de la réponse. S'il vous plaît, apprenez de vos erreurs (et avant cela, essayez de les comprendre) au lieu d'être têtu. Être un bon garçon est également incompatible avec la diffusion de mauvaises pratiques.
gniourf_gniourf
1
Ou, si vous utilisez Bash ≥4, vous n'avez pas besoin de tr:if [[ $S =~ ^([^[:alpha:]]*)([[:alpha:]].*) ]]; then out=${BASH_REMATCH[1]}${BASH_REMATCH[2]^}; else out=$S; fi; printf '%s\n' "$out"
gniourf_gniourf
5
Ce code est toujours mal rompu. Il utilise toujours des backticks au lieu de la syntaxe de substitution moderne; il a toujours des citations incomparables; il y a encore des citations manquantes là où elles importent réellement ; etc. Essayez de mettre des caractères glob dans vos données de test, si vous ne pensez pas que ces guillemets manquants font une différence, et corrigez les problèmes que shellcheck.net trouve jusqu'à ce que ce code soit clair .
Charles Duffy
2
Quant au langage que vous avez cité sur unix.stackexchange.com/questions/68694/… , ce qui vous manque, c'est qu'il echo $foos'agit d'un exemple de situation où l'analyseur attend une liste de mots ; Ainsi, dans votre echo ${F}, le contenu de Fest divisé en chaîne et étendu globalement. C'est également vrai pour l' echo ${S:$N:1}exemple et tout le reste. Voir BashPitfalls # 14 .
Charles Duffy