wielka pierwsza litera w zmiennej z bash


Odpowiedzi:


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

2
Pomimo tego, że jest bardziej złożona niż najlepiej oceniona odpowiedź, ta w rzeczywistości robi dokładnie to: „pierwszy wielki znak w zmiennej”. Najlepsza odpowiedź nie daje takich wyników. Wygląda na to, że proste odpowiedzi są głosowane chętniej niż te prawidłowe?
Krzysztof Jabłoński

15
@ KrzysztofJabłoński: Właściwie "najlepiej punktowana odpowiedź" poniżej da takie same wyniki jak ta odpowiedź w Bash 4. Ta odpowiedź ma narzut wywołania podpowłoki (kolejnej powłoki), narzut wywołania narzędzia "tr" (inny proces , a nie Bash), narzut związany z użyciem tutaj-doc / string (tymczasowe tworzenie pliku) i używa dwóch podstawień w porównaniu z jedną z najlepiej ocenioną odpowiedzią. Jeśli absolutnie musisz napisać starszy kod, rozważ użycie funkcji zamiast podpowłoki.
Steve

2
Ta odpowiedź zakłada, że ​​dane wejściowe są zapisane małymi literami. Ten wariant nie ma żadnych założeń: $ (tr '[: lower:]' '[: upper:]' <<< $ {foo: 0: 1}) $ (tr '[: upper:]' '[: lower: ] '<<< $ {foo: 1})
Itai Hanski

5
@ItaiHanski OP nie określił, co powinno stać się z pozostałymi postaciami, tylko z pierwszą. Niby chcieli zmienić notQuiteCamelsię NotQuiteCamel. Twój wariant ma efekt uboczny lub zmusza pozostałe do małych liter - kosztem podwojenia liczby podpowłok i procesów tr.
Jesse Chisholm

3
@DanieleOrlando, to prawda, ale to pytanie nie ma innych tagów niż bash.
Charles Duffy,

314

W jedną stronę z bash (wersja 4+):

foo=bar
echo "${foo^}"

wydruki:

Bar

2
Czy jest coś przeciwnego?
CMCDragonkai

44
@CMCDragonkai: Aby zamienić pierwszą literę na małą, użyj "${foo,}". Aby wszystkie litery były małe, użyj "${foo,,}". Aby wszystkie litery były wielkie, użyj "${foo^^}".
Steve

1
Przypadkowo to zauważyłem ${foo~}i ${foo~~}mam taki sam efekt jak ${foo^}i ${foo^^}. Ale nigdy nie widziałem tej alternatywy nigdzie wspomnianej.
mivk

5
to nie działa na komputerach Mac. otrzymuję następujący błąd:bad substitution
Toland Hon

1
@TolandHon: Jak zapewne już się przekonałeś, musisz zaktualizować do wersji 4.x lub wypróbować inne rozwiązanie, jeśli z jakiegoś powodu nie można zaktualizować tego komputera.
Steve

29

W jedną stronę z sed:

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

Wydruki:

Bar

10
nie działa na MacOS10 Lion sed, westchnij, \ u rozszerza się do u zamiast być operatorem.
vwvan

2
@vwvan brew install coreutils gnu-sedi postępuj zgodnie z instrukcjami, aby użyć poleceń bez prefiksu g. Na ile to warte, nigdy nie chciałem uruchamiać wersji tych poleceń dla OSX od czasu otrzymania wersji GNU.
Dziekan

@vwvan: Tak, przepraszam, sedw tym przypadku będziesz potrzebować GNU
Steve

2
@Dean: FWIW, nigdy nie chciałem uruchamiać OSX :-)
Steve

5
Po prostu zmień to na sed 's/./\U&/i będzie działać na POSIX sed.
David Conrad


14

Oto "natywne" narzędzia tekstowe:

#!/bin/bash

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

wreszcie coś, co działa ze zmienną i na Macu! Dziękuję Ci!
OZZIE

4
@DanieleOrlando, nie tak przenośne, jak można by się spodziewać. tr [:lower:] [:upper:]jest lepszym wyborem, jeśli musi działać w języku / ustawieniach regionalnych zawierających litery spoza zakresu a-zlub A-Z.
Charles Duffy

8

Używanie tylko awk

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

wynik: Uncapitalizedstring
Alex Freshmann

4

Można to zrobić również w czystym bashu z 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}"

jak zdefiniować foo? Próbowałem, foo = $1ale dostaję tylko-bash: foo: command not found
OZZIE

1
@OZZIE, brak spacji wokół =w zadaniach. To jest coś, co shellcheck.net znajdzie dla Ciebie programowo.
Charles Duffy

Zawsze zapominam o skryptach powłoki .. tylko język, w którym liczy się jedna spacja (przed / po) ... westchnij (python to co najmniej 4, jeśli dobrze pamiętam)
OZZIE

@OZZIE, to musi mieć znaczenie, bo gdyby to nie miało znaczenia, nie można by przekazać =jako argumentu do programu (skąd ma wiedzieć, czy someprogram =działa someprogram, czy przypisać do zmiennej o nazwie someprogram?)
Charles Duffy

3

To też działa ...

FooBar=baz

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

=> Baz
FooBar=baz

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

=> bAz
FooBar=baz

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

=> baZ

I tak dalej.

Źródła:

Wprowadzenie / samouczki:


3

Aby pisać wielką literą tylko pierwsze słowo:

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

O ne dwa, trzy


Aby zapisać każde słowo w zmiennej wielką literą :

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

O ne T wo T hree


(działa w bash 4+)


foo='one two three'; foo=$(for i in $foo; do echo -n "${i^} "; done) Mniejsza rozdzielczość dla każdego słowa. foo Now to „One Two Three”
vr286

Jak mogę zamienić pierwsze 3 lub 4 wielkie litery na wielkie? Jak PQRS-123-v1 do PQRS-123-v1 ? Albo możesz powiedzieć, wszystkie litery przed pierwszym myślnikiem ...
Vicky Dev

2

Alternatywne i czyste rozwiązanie zarówno dla Linuksa, jak i OSX, może być również używane ze zmiennymi bash

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

zwraca Abc


0

Ten pracował dla mnie:

Wyszukiwanie wszystkich plików * php w bieżącym katalogu i zamień pierwszy znak każdej nazwy pliku na wielką literę:

np .: test.php => Test.php

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

4
Pierwotne pytanie było ciągiem znaków i nie zawierało odniesienia do zmiany nazw plików.
AndySavage,

0

tylko dla zabawy, oto jesteś:

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

Nie dokładnie to, o co pytano, ale całkiem pomocne

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

foo=bar
echo $foo
BAR

I odwrotnie

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 - schowek wyboru}


-7

Co się stanie, jeśli pierwszy znak nie jest literą (ale tabulatorem, spacją i podwójnym cudzysłowem ze znakiem ucieczki)? Lepiej to przetestujmy , znajdziemy list! Więc:

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
Proszę napisać bardziej przejrzysty kod! brakuje ci cytatów w każdym miejscu. Używasz przestarzałej składni (lewych apostrofów); używasz przestarzałej składni ( $[...]). Używasz wielu bezużytecznych nawiasów. Zakładasz, że ciąg składa się ze znaków alfabetu łacińskiego (co powiesz na litery akcentowane lub litery z innych alfabetów?). Masz dużo pracy, aby uczynić ten fragment kodu użytecznym! (a ponieważ używasz wyrażenia regularnego, równie dobrze możesz użyć wyrażenia regularnego do znalezienia pierwszej litery zamiast pętli).
gniourf_gniourf

6
Myślę, że jesteś w błędzie. To obowiązkowy komentarz, który towarzyszy głosowaniu przeciw, wyjaśniając wszystkie niewłaściwe wzorce i błędne wyobrażenia o odpowiedzi. Proszę, ucz się na swoich błędach (a wcześniej spróbuj je zrozumieć) zamiast być upartym. Bycie dobrym człowiekiem jest również niezgodne z szerzeniem złych praktyk.
gniourf_gniourf

1
Lub, jeśli używasz Bash ≥4, nie potrzebujesz tr:if [[ $S =~ ^([^[:alpha:]]*)([[:alpha:]].*) ]]; then out=${BASH_REMATCH[1]}${BASH_REMATCH[2]^}; else out=$S; fi; printf '%s\n' "$out"
gniourf_gniourf

5
Ten kod jest nadal mocno uszkodzony. Nadal używa znaków odwrotnych zamiast nowoczesnej składni podstawiania; nadal ma niezrównane cytaty; nadal brakuje cudzysłowów w miejscach, w których mają one znaczenie ; itp. Spróbuj wstawić do danych testowych kilka znaków glob otoczonych białymi spacjami, jeśli nie uważasz, że te brakujące cudzysłowy mają znaczenie, i napraw problemy znalezione przez shellcheck.net, dopóki kod nie będzie czysty.
Charles Duffy

2
Jeśli chodzi o język, który zacytowałeś z unix.stackexchange.com/questions/68694/… , to brakuje ci tego, że echo $foojest to przykład sytuacji, w której parser oczekuje listy słów ; więc w twoim echo ${F}, zawartość Fjest dzielona na łańcuchy i rozszerzana globalnie. Podobnie jest w przypadku echo ${S:$N:1}przykładu i całej reszty. Zobacz BashPitfalls # 14 .
Charles Duffy
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.