Перший символ верхнього регістру в змінній з bash


162

Я хочу прописати лише великі літери в моєму рядку з bash.

foo="bar";

//uppercase first character

echo $foo;

слід надрукувати "Бар";


1
Це не точний дублікат, але багато методів, описаних у перетворенні рядка в малі регістри в сценарії Bash shell, також можуть бути застосовані до цієї проблеми.
pjh

Відповіді:


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

2
Незважаючи на те, що є більш складною, ніж найкраще набрана відповідь, цей насправді робить саме це: "першим великим символом у змінній". Найкраща відповідь не має цих результатів. Схоже, що прості відповіді оскаржуються більш охоче, ніж правильні?
Кшиштоф Яблонський

15
@ KrzysztofJabłoński: Насправді, "найкраще набрана відповідь" нижче дасть ті самі результати, що і ця відповідь під Bash 4. Ця відповідь має накладні витрати на виклик підзарядки (іншої оболонки), накладні витрати на виклик утиліти "tr" (інший процес , а не Bash), накладні витрати на використання тут-doc / string (створення тимчасового файлу), і він використовує дві заміни порівняно з найкращим набраним відповіддю. Якщо ви обов'язково повинні написати застарілий код, подумайте про використання функції замість нижньої частини.
Стів

2
Ця відповідь припускає, що всі вхідні регістри є вхідними. Цей варіант не має припущень: $ (tr '[: нижній:]' '[: верхній:]' <<< $ {foo: 0: 1}) $ (tr '[: верхній:]' '[: нижній: ] '<<< $ {foo: 1})
Itai Hanski

5
@ItaiHanski ОП не вказала, що має статися з рештою персонажами, лише першими. Припустимо, вони хотіли перетворитися notQuiteCamelна NotQuiteCamel. Ваш варіант має побічний ефект або примушує решту до малих рекордів - ціною подвоєння кількості додаткових оболонок і тр.
Jesse Chisholm

3
@DanieleOrlando, правда, але це питання не має інших тегів bash.
Чарльз Даффі

314

Один спосіб з bash (версія 4+):

foo=bar
echo "${foo^}"

відбитки:

Bar

2
Чи існує протилежність цьому?
CMCDragonkai

44
@CMCDragonkai: Щоб записати першу букву, використовуйте "${foo,}". Щоб прописати всі літери, використовуйте "${foo,,}". Для великих літер використовуйте великі літери "${foo^^}".
Стів

1
Я випадково помітив це ${foo~}і ${foo~~}має такий же ефект, як ${foo^}і ${foo^^}. Але я ніде не бачив такої альтернативи, згаданої ніде.
mivk

5
це не працює на Mac. отримую таку помилку:bad substitution
Toland Hon

1
@TolandHon: Як ви, напевно, вже працювали, вам потрібно буде оновити версію 4.x або спробувати інше рішення, якщо цю машину з якихось причин не вдасться оновити.
Стів

29

Один із способів sed:

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

Друкує:

Bar

10
не працює на MacOS10 Lion sed, зітхаючи, \ u розширюється до u замість того, щоб бути оператором.
vwvan

2
@vwvan brew install coreutils gnu-sedі дотримуйтесь інструкцій щодо використання команд без префікса g. Чого варто, я ніколи не хотів запускати версію OSX цих команд з моменту отримання версій GNU.
Дін

@vwvan: Так, вибачте, GNU вам знадобиться sedв цьому випадку
Стів

2
@Dean: FWIW, я ніколи не хотів запускати OSX :-)
Стів

5
Просто змініть його на sed 's/./\U&/і він працюватиме на POSIX sed.
Девід Конрад


14

Ось "рідний" спосіб текстових інструментів:

#!/bin/bash

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

нарешті щось, що працює зі змінною та на Mac! Дякую!
OZZIE

4
@DanieleOrlando, не настільки портативний, як можна сподіватися. tr [:lower:] [:upper:]є кращим вибором, якщо йому потрібно працювати в мові / локалі, включаючи букви, яких немає в діапазоні a-zабо A-Zдіапазоні.
Чарльз Даффі

8

Використовуючи лише awk

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

результат: Некапіталізований рядок
Alex Freshmann

4

Це також можна зробити в чистому стилі з 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}"

як визначити foo? Я спробував, foo = $1але тільки отримую-bash: foo: command not found
OZZIE

1
@OZZIE, =у завданнях немає пробілів . Це те, що shellcheck.net знайде для вас програмно.
Чарльз Даффі

Я завжди забуваю, що про сценарії оболонки .. тільки мова, де має місце пробіл (до / після) ... зітхнення (python - принаймні 4, якщо я правильно пам’ятаю)
OZZIE

@OZZIE, це має значення, тому що якщо це не мало значення, ти не можеш передати =як аргумент програмі (як він повинен знати, чи someprogram =працює someprogram, або присвоїти змінну на ім'я someprogram?)
Чарльз Даффі

3

Це теж працює ...

FooBar=baz

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

=> Baz
FooBar=baz

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

=> bAz
FooBar=baz

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

=> baZ

І так далі.

Джерела:

Введення / Підручники:


3

Використовуйте великі літери лише для першого слова:

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

О не два три


Щоб використовувати великі літери у кожному змінному:

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

O ne T wo T hree


(працює в bash 4+)


foo='one two three'; foo=$(for i in $foo; do echo -n "${i^} "; done) Коротше роздільна здатність кожного слова. foo Зараз "Один Дві Три"
vr286

Як я можу використовувати великі регістри перших 3 чи 4 букв на великі літери? Як і pqrs-123-v1 до PQRS-123-v1 ? Або ви можете сказати, всі букви перед першою дефісом ...
Вікі Дев

2

Альтернативне і чисте рішення як для Linux, так і для OSX, воно також може використовуватися з bash змінними

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

повертає Abc


0

Цей працював на мене:

Пошук усіх * php-файлів у поточному каталозі та замінення першого символу кожного імені файлу на велику літеру:

наприклад: test.php => Test.php

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

4
Оригінальне запитання було рядком і не посилалось на перейменування файлів.
AndySavage

0

просто для розваги ось ви:

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

Не зовсім те, що просили, але цілком корисно

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

foo=bar
echo $foo
BAR

І навпаки

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
}

перша буква-до-нижня-xc () {v-перша-буква-до-нижня | xclip - вибір буфера обміну}


-7

Що робити, якщо перший символ - це не буква (а вкладка, пробіл та уникнута подвійна цитата)? Ми краще перевіримо його, поки не знайдемо листа! Так:

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
Будь ласка, напишіть чистіший код! тобі не вистачає цитат по всьому місцю. Ви використовуєте застарілий синтаксис (backticks); ви використовуєте синтаксис ( $[...]). Ви використовуєте безліч марних дужок. Ви припускаєте, що рядок складається з символів з латинського алфавіту (як щодо наголошених букв чи букв інших алфавітів?). Ви маєте велику роботу, щоб зробити цей фрагмент корисним! (а оскільки ви використовуєте регулярний вираз, ви можете також використовувати регулярний вираз, щоб знайти першу літеру, а не цикл).
gniourf_gniourf

6
Я думаю, ти помилявся. Це обов'язковий коментар, який супроводжує голосування, пояснюючи всі неправильні закономірності та неправильні уявлення про відповідь. Будь ласка, вчіться на своїх помилках (а перед цим намагайтеся їх зрозуміти), а не впертим. Бути добрим товаришем також не сумісний із поширенням поганих практик.
gniourf_gniourf

1
Або якщо ви використовуєте Bash ≥4, вам не потрібно tr:if [[ $S =~ ^([^[:alpha:]]*)([[:alpha:]].*) ]]; then out=${BASH_REMATCH[1]}${BASH_REMATCH[2]^}; else out=$S; fi; printf '%s\n' "$out"
gniourf_gniourf

5
Цей код все ще сильно порушений. Він все ще використовує зворотні посилання замість сучасного синтаксису заміни; досі є незрівнянні цитати; у ньому все ще відсутні цитати в місцях, де вони насправді мають значення ; Спробуйте ввести деякі тестові глобусні символи у ваші тестові дані, якщо ви не вірите, що ці пропущені цитати мають значення, і виправте проблеми, знайдені shellcheck.net, поки цей код не з’явиться чистим.
Чарльз Даффі

2
Що стосується мови, яку ви цитували з unix.stackexchange.com/questions/68694/… , те, що ви сумуєте, echo $foo- це приклад ситуації, коли аналізатор очікує список слів ; тож у вашому echo ${F}вмісті Fрозділено на рядки та розширюється по всьому світу . Це так само стосується echo ${S:$N:1}прикладу та всіх інших. Дивіться BashPitfalls №14 .
Чарльз Даффі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.