huruf besar pertama dalam variabel dengan bash


162

Saya ingin huruf besar hanya karakter pertama di string saya dengan bash.

foo="bar";

//uppercase first character

echo $foo;

harus mencetak "Bar";


1
Ini bukan duplikat yang tepat, tetapi banyak teknik yang dijelaskan dalam Konversi string ke huruf kecil dalam skrip Bash shell juga dapat diterapkan untuk masalah ini.
pjh

Jawaban:


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

2
Meskipun lebih kompleks daripada jawaban skor terbaik, yang satu ini benar-benar melakukan hal itu: 'huruf pertama dalam variabel'. Jawaban skor terbaik tidak memiliki hasil itu. Sepertinya jawaban sederhana lebih dipilih secara sukarela daripada jawaban yang benar?
Krzysztof Jabłoński

15
@ KrzysztofJabłoński: Sebenarnya, "jawaban dengan skor terbaik" di bawah ini akan menghasilkan hasil yang sama dengan jawaban ini di bawah Bash 4. Jawaban ini memiliki overhead untuk memanggil subkulit (shell lain), overhead untuk memanggil utilitas 'tr' (proses lain , bukan Bash), overhead menggunakan di sini-doc / string (pembuatan file sementara) dan menggunakan dua substitusi dibandingkan dengan yang terbaik jawaban jawaban. Jika Anda benar-benar harus menulis kode lawas, pertimbangkan untuk menggunakan fungsi alih-alih subkulit.
Steve

2
Jawaban ini mengasumsikan input semua huruf kecil. Varian ini tidak memiliki asumsi: $ (tr '[: lebih rendah:]' '[: atas:]' <<< $ {foo: 0: 1}) $ (tr '[: atas:]' '[: lebih rendah: ] '<<< $ {foo: 1})
Itai Hanski

5
@ItaiHanski OP tidak menentukan apa yang harus terjadi pada karakter yang tersisa, hanya yang pertama. Seharusnya mereka ingin berubah notQuiteCamelmenjadi NotQuiteCamel. Varian Anda memiliki efek samping atau memaksa sisanya menjadi huruf kecil - dengan biaya menggandakan jumlah subkulit dan proses tr.
Jesse Chisholm

3
@DanieleOrlando, benar, tetapi pertanyaan ini tidak memiliki tag selain bash.
Charles Duffy

314

Satu arah dengan bash (versi 4+):

foo=bar
echo "${foo^}"

cetakan:

Bar

2
Apakah ada yang bertentangan dengan ini?
CMCDragonkai

44
@ CMCDragonkai: Untuk huruf kecil huruf pertama, gunakan "${foo,}". Untuk huruf kecil semua huruf, gunakan "${foo,,}". Untuk huruf besar semua huruf, gunakan "${foo^^}".
Steve

1
Saya tidak sengaja memperhatikan itu ${foo~}dan ${foo~~}memiliki efek yang sama seperti ${foo^}dan ${foo^^}. Tetapi saya tidak pernah melihat alternatif itu disebutkan di mana pun.
mivk

5
ini sepertinya tidak berfungsi pada Mac. mendapatkan kesalahan berikut:bad substitution
Toland Hon

1
@TolandHon: Karena Anda mungkin sudah berolahraga, Anda harus meningkatkan ke versi 4.x, atau mencoba solusi lain jika mesin itu tidak dapat ditingkatkan karena alasan tertentu.
Steve

29

Satu cara dengan sed:

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

Cetakan:

Bar

10
tidak berfungsi pada MacOS10 Lion, huh, \ u memperluas ke Anda alih-alih menjadi operator.
vwvan

2
@vwvan brew install coreutils gnu-seddan ikuti instruksi untuk menggunakan perintah tanpa awalan g. Untuk apa nilainya saya tidak pernah ingin menjalankan versi OSX dari perintah ini sejak mendapatkan versi GNU.
Dean

@vwvan: Ya, maaf, Anda membutuhkan GNU seddalam hal ini
Steve

2
@Dean: FWIW, saya tidak pernah ingin menjalankan OSX :-)
Steve

5
Cukup ubah sed 's/./\U&/dan akan berfungsi pada POSIX sed.
David Conrad

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

14

Berikut ini cara alat teks "asli":

#!/bin/bash

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

akhirnya sesuatu yang bekerja dengan variabel dan di Mac! Terima kasih!
OZZIE

4
@DanieleOrlando, tidak portabel seperti yang diharapkan. tr [:lower:] [:upper:]adalah pilihan yang lebih baik jika perlu bekerja dalam bahasa / lokal memasukkan huruf yang tidak ada dalam a-zatau A-Zrentang.
Charles Duffy

8

Hanya menggunakan awk

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

hasil: Uncapitalizedstring
Alex Freshmann

4

Ini dapat dilakukan dalam bash murni dengan bash-3.2 juga:

# 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}"

bagaimana cara mendefinisikan foo? Saya mencoba foo = $1tetapi saya hanya mendapatkan-bash: foo: command not found
OZZIE

1
@OZZIE, tidak ada spasi di sekitar =tugas dalam. Ini adalah sesuatu yang shellcheck.net akan temukan untuk Anda secara terprogram .
Charles Duffy

Saya selalu lupa bahwa tentang skrip shell .. hanya bahasa di mana satu spasi (sebelum / sesudah) penting ... sigh (python setidaknya 4 jika saya ingat dengan benar)
OZZIE

@OZZIE, itu memiliki untuk peduli, karena jika tidak masalah, Anda tidak bisa lulus =sebagai argumen untuk program (bagaimana cara seharusnya tahu jika someprogram =sedang berjalan someprogram, atau menugaskan ke variabel bernama someprogram?)
Charles Duffy


3

Hanya menggunakan huruf kapital untuk kata pertama:

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

O ne dua tiga


Untuk mengkapitalisasi setiap kata dalam variabel:

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

O ne T wo T hree


(bekerja di bash 4+)


foo='one two three'; foo=$(for i in $foo; do echo -n "${i^} "; done) Resolusi lebih pendek untuk setiap kata. foo Sekarang adalah "One Two Three"
vr286

Bagaimana saya bisa menggunakan huruf besar 3 atau 4 pertama untuk huruf besar? Suka pqrs-123-v1 ke PQRS-123-v1 ? Atau Anda bisa mengatakan, semua huruf sebelum tanda hubung pertama ...
Vicky Dev

2

Alternatif dan solusi bersih untuk Linux dan OSX, dapat juga digunakan dengan variabel bash

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

mengembalikan Abc


0

Yang ini bekerja untuk saya:

Mencari semua * file php di direktori saat ini, dan ganti karakter pertama dari setiap nama file dengan huruf kapital:

misal: test.php => Test.php

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

4
Pertanyaan aslinya adalah string, dan tidak membuat referensi untuk mengubah nama file.
AndySavage

0

hanya untuk bersenang-senang di sini Anda berada:

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

Tidak persis apa yang diminta tetapi sangat membantu

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

foo=bar
echo $foo
BAR

Dan sebaliknya

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-clipboard pilihan}


-7

Bagaimana jika karakter pertama bukan huruf (tetapi tab, spasi, dan kutipan ganda yang lolos)? Lebih baik kita menguji itu sampai kita menemukan surat! Begitu:

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
Silakan tulis kode bersih! Anda kekurangan kutipan di semua tempat. Anda menggunakan sintaks yang usang (backticks); Anda menggunakan sintaks antiquated ( $[...]). Anda menggunakan banyak tanda kurung yang tidak berguna. Anda mengasumsikan bahwa string terdiri dari karakter dari alfabet latin (bagaimana dengan huruf aksentuasi, atau huruf dalam huruf lain?). Anda memiliki banyak pekerjaan untuk membuat cuplikan ini dapat digunakan! (dan karena Anda menggunakan regex, Anda mungkin juga menggunakan regex untuk menemukan huruf pertama, bukan loop).
gniourf_gniourf

6
Saya pikir kamu salah. Ini adalah komentar wajib yang menyertai downvote, menjelaskan semua pola yang salah dan kesalahpahaman dari jawaban. Tolong, pelajari dari kesalahan Anda (dan sebelum itu, cobalah untuk memahaminya) daripada menjadi keras kepala. Menjadi orang baik juga tidak cocok dengan menyebarkan praktik buruk.
gniourf_gniourf

1
Atau, jika menggunakan Bash ≥4, Anda tidak perlu tr :if [[ $S =~ ^([^[:alpha:]]*)([[:alpha:]].*) ]]; then out=${BASH_REMATCH[1]}${BASH_REMATCH[2]^}; else out=$S; fi; printf '%s\n' "$out"
gniourf_gniourf

5
Kode ini masih rusak parah. Itu masih menggunakan backticks alih-alih sintaks substitusi modern; masih memiliki kutipan yang tak tertandingi; masih memiliki tanda kutip yang hilang di tempat-tempat di mana mereka sebenarnya penting ; dll. Cobalah memasukkan beberapa karakter glob yang dikelilingi ruang kosong ke dalam data pengujian Anda, jika Anda tidak percaya bahwa kutipan yang hilang itu membuat perbedaan, dan perbaiki masalah shellcheck.net ditemukan hingga kode ini muncul bersih.
Charles Duffy

2
Adapun bahasa yang Anda kutip dari unix.stackexchange.com/questions/68694/… , yang Anda lewatkan adalah echo $foocontoh situasi di mana pengurai mengharapkan daftar kata-kata ; jadi di Anda echo ${F}, isi Fstring-split dan glob-diperluas. Hal yang sama berlaku untuk echo ${S:$N:1}contoh dan yang lainnya. Lihat BashPitfalls # 14 .
Charles Duffy
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.