primeiro caractere maiúsculo em uma variável com bash


Respostas:


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

2
Apesar de ser mais complexo do que a resposta melhor pontuada, esta realmente faz exatamente isso: 'primeiro caractere maiúsculo de uma variável'. A resposta com melhor pontuação não possui esses resultados. Parece que respostas simples são votadas com mais vontade do que as corretas?
Krzysztof Jabłoński 26/02

15
@ KrzysztofJabłoński: Na verdade, a "resposta mais bem classificada" abaixo produzirá os mesmos resultados que esta resposta no Bash 4. Essa resposta tem a sobrecarga de chamar um subshell (outro shell), a sobrecarga de chamar o utilitário 'tr' (outro processo , não Bash), a sobrecarga do uso de aqui-doc / string (criação temporária de arquivo) e usa duas substituições em comparação com a resposta com a melhor pontuação. Se você absolutamente precisar escrever código legado, considere usar uma função em vez de um subshell.
Steve Steve

2
Esta resposta assume que a entrada está em letras minúsculas. Esta variante não possui suposições: $ (tr '[: lower:]' '[: upper:]' <<< $ {foo: 0: 1}) $ (tr '[: upper:]' '[: lower: ] '<<< $ {foo: 1})
Itai Hanski

5
@ItaiHanski O OP não especificou o que deveria acontecer com os personagens restantes, apenas o primeiro. Supunha que queria mudar notQuiteCamelem NotQuiteCamel. Sua variante tem o efeito colateral ou força o restante a minúsculo - ao custo de dobrar o número de subcascas e processos tr.
Jesse Chisholm

3
@DanieleOrlando, é verdade, mas esta pergunta não tem tags além de bash.
Charles Duffy

313

Uma maneira com o bash (versão 4+):

foo=bar
echo "${foo^}"

impressões:

Bar

2
Existe um oposto disso?
CMCDragonkai

44
@CMCDragonkai: Para minúscula a primeira letra, use "${foo,}". Para minúsculas todas as letras, use "${foo,,}". Para colocar todas as letras em maiúsculas, use "${foo^^}".
Steve

1
Eu notei isso acidentalmente ${foo~}e ${foo~~}tem o mesmo efeito que ${foo^}e ${foo^^}. Mas nunca vi essa alternativa mencionada em nenhum lugar.
mivk

5
isso parece não funcionar em Macs. recebendo o seguinte erro:bad substitution
Toland Hon

1
@TolandHon: Como você provavelmente já trabalhou, precisará atualizar para a versão 4.x ou tentar outra solução se essa máquina não puder ser atualizada por algum motivo.
21419 Steve Steve

29

Uma maneira com sed:

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

Impressões:

Bar

10
não funciona no MacOS10 Lion sed, suspiro, o \ u se expande para u em vez de ser um operador.
vwvan

2
@vwvan brew install coreutils gnu-sede siga as instruções para usar os comandos sem o prefixo g. Pelo que vale a pena, eu nunca quis executar a versão OSX desses comandos desde a obtenção das versões GNU.
Dean

@vwvan: Sim, desculpe, você vai precisar GNU sedneste caso
Steve

2
@Dean: FWIW, eu nunca quis correr OSX :-)
Steve

5
Apenas mude para sed 's/./\U&/e ele funcionará no POSIX sed.
David Conrad

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

14

Aqui está a maneira "nativa" das ferramentas de texto:

#!/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 com uma variável e no Mac! Obrigado!
OZZIE

4
@DanieleOrlando, não tão portátil quanto se poderia esperar. tr [:lower:] [:upper:]é uma escolha melhor se precisar trabalhar em idiomas / localidades que incorporem letras que não estão nos intervalos a-zou A-Z.
Charles Duffy

8

Usando apenas awk

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

resultado: Uncapitalizedstring
Alex Freshmann

4

Isso também pode ser feito no bash puro com o 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}"

como definir foo? Eu tentei, foo = $1mas só consigo-bash: foo: command not found
OZZIE

1
@OZZIE, não há espaços ao redor das =tarefas. Isso é algo que o shellcheck.net encontrará para você programaticamente.
Charles Duffy

Eu sempre esqueço que cerca de shell scripts .. única língua onde um espaço (antes / depois) questões ... suspirar (python é pelo menos 4 se bem me lembro)
OZZIE

@OZZIE, ele tem à matéria, porque se ele não importa, você não poderia passar =como um argumento para um programa (como é suposto saber se someprogram =está em execução someprogram, ou atribuir a uma variável chamada someprogram?)
Charles Duffy

3

Isso funciona também ...

FooBar=baz

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

=> Baz
FooBar=baz

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

=> bAz
FooBar=baz

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

=> baZ

E assim por diante.

Fontes:

Introduções / Tutoriais:


3

Para colocar em maiúscula apenas a primeira palavra:

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

O ne dois três


Para colocar em maiúscula todas as palavras na variável:

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

O ne t wo t rês


(funciona no bash 4+)


foo='one two three'; foo=$(for i in $foo; do echo -n "${i^} "; done) Resolução mais curta para cada palavra. foo Agora é "um dois três"
vr286

2

Solução alternativa e limpa para Linux e OSX, também pode ser usada com variáveis ​​bash

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

retorna Abc


0

Este funcionou para mim:

Procurando por todos os arquivos * php no diretório atual e substitua o primeiro caractere de cada nome de arquivo por letra maiúscula:

por exemplo: test.php => Test.php

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

4
A pergunta original era uma sequência e não fazia referência à renomeação de arquivos.
21717 AndySavage

0

apenas por diversão, aqui está você:

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

Não é exatamente o que pediu, mas é 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

E o oposto

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
}

primeira letra para abaixar xc () {v-primeira letra para abaixar | xclip -selection clipboard}


-7

E se o primeiro caractere não for uma letra (mas uma tabulação, espaço e aspas duplas)? É melhor testá- lo até encontrarmos uma carta! Assim:

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=

6
Por favor, escreva um código mais limpo! faltam citações em todo o lugar. Você está usando sintaxe obsoleta (backticks); você está usando sintaxe antiquada ( $[...]). Você está usando muitos parênteses inúteis. Você está assumindo que a sequência consiste em caracteres do alfabeto latino (que tal letras acentuadas ou em outros alfabetos?). Você tem muito trabalho para tornar esse trecho utilizável! (e como você está usando regex, você pode usá-lo para encontrar a primeira letra, em vez de um loop).
91117 Gnourf_gniourf

6
Eu acho que você está errado. É o comentário obrigatório que acompanha o voto negativo, explicando todos os padrões e conceitos errados da resposta. Por favor, aprenda com seus erros (e antes disso, tente entendê-los) em vez de ser teimoso. Ser um bom companheiro também é incompatível com a disseminação de más práticas.
911717 Gnourf_gniourf # 94417

1
Ou, se você estiver usando o Bash ≥4, não precisará tr:if [[ $S =~ ^([^[:alpha:]]*)([[:alpha:]].*) ]]; then out=${BASH_REMATCH[1]}${BASH_REMATCH[2]^}; else out=$S; fi; printf '%s\n' "$out"
gniourf_gniourf

5
Este código ainda está muito quebrado. Ainda está usando backticks em vez da sintaxe de substituição moderna; ele ainda possui aspas incomparáveis; ainda faltam citações em lugares onde elas realmente importam ; etc. Tente colocar alguns caracteres glob cercados de espaço em branco em seus dados de teste, se você não acredita que essas aspas ausentes façam diferença, e corrija os problemas encontrados pelo shellcheck.net até que esse código seja limpo.
Charles Duffy

2
Quanto ao idioma que você citou em unix.stackexchange.com/questions/68694/… , o que você sente falta é que echo $fooé um exemplo de uma situação em que o analisador espera uma lista de palavras ; Assim, no seu echo ${F}, o conteúdo de Fé dividido por cadeias e expandido por glob. O mesmo se aplica ao echo ${S:$N:1}exemplo e a todo o resto. Veja BashPitfalls # 14 .
Charles Duffy
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.