chữ hoa đầu tiên trong một biến với bash


Câu trả lời:


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

2
Mặc dù phức tạp hơn câu trả lời được ghi điểm tốt nhất, nhưng câu trả lời này thực sự làm chính xác điều đó: 'ký tự đầu tiên viết hoa trong một biến'. Câu trả lời tốt nhất không có kết quả đó. Có vẻ như câu trả lời đơn giản được nâng cao sẵn sàng hơn câu trả lời đúng?
Krzysztof Jabłoński

15
@ KrzysztofJabłoński: Trên thực tế, "câu trả lời được ghi điểm tốt nhất" dưới đây sẽ tạo ra kết quả tương tự như câu trả lời này theo Bash 4. Câu trả lời này có chi phí gọi một subshell (vỏ khác), chi phí gọi cho tiện ích 'tr' (một quá trình khác , không phải Bash), chi phí sử dụng một tài liệu / chuỗi ở đây (tạo tệp tạm thời) và nó sử dụng hai thay thế so với câu trả lời được ghi điểm tốt nhất. Nếu bạn hoàn toàn phải viết mã kế thừa, hãy xem xét sử dụng một hàm thay vì một lớp con.
Steve

2
Câu trả lời này giả sử đầu vào là tất cả chữ thường. Biến thể này không có giả định: $ (tr '[: Lower:]' '[: Upper:]' <<< $ {foo: 0: 1}) $ (tr '[: Upper:]' '[: Lower: ] '<<< $ {foo: 1})
Itai Hanski

5
@ItaiHanski OP không chỉ định điều gì sẽ xảy ra với các ký tự còn lại, chỉ là ký tự đầu tiên. Giả sử họ muốn đổi notQuiteCamelthành NotQuiteCamel. Biến thể của bạn có tác dụng phụ hoặc buộc phần còn lại thành chữ thường - với chi phí nhân đôi số lượng vỏ phụ và quy trình tr.
Jesse Chisholm

3
@DanieleOrlando, đúng, nhưng câu hỏi này không có thẻ nào khác ngoài bash.
Charles Duffy

313

Một cách với bash (phiên bản 4+):

foo=bar
echo "${foo^}"

in:

Bar

2
Có một điều ngược lại với điều này?
CMCDragonkai

44
@CMCDragonkai: Để viết thường chữ cái đầu tiên, sử dụng "${foo,}". Để viết thường tất cả các chữ cái, sử dụng "${foo,,}". Để viết hoa tất cả các chữ cái, sử dụng "${foo^^}".
Steve

1
Tôi vô tình nhận thấy điều đó ${foo~}${foo~~}có tác dụng tương tự như ${foo^}${foo^^}. Nhưng tôi không bao giờ thấy sự thay thế được đề cập ở bất cứ đâu.
mivk

5
điều này dường như không hoạt động trên máy Mac. nhận được lỗi sau:bad substitution
Toland Hon

1
@TolandHon: Vì có lẽ bạn đã làm việc xong, bạn sẽ cần nâng cấp lên phiên bản 4.x hoặc thử một giải pháp khác nếu máy đó không thể được nâng cấp vì một số lý do.
Steve

29

Một cách với sed:

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

Bản in:

Bar

10
không hoạt động trên MacOS10 Lion sed, thở dài, \ u mở rộng ra u thay vì là một nhà điều hành.
vwvan

2
@vwvan brew install coreutils gnu-sedvà làm theo hướng dẫn để sử dụng các lệnh mà không cần tiền tố g. Đối với những gì đáng giá tôi chưa bao giờ muốn chạy phiên bản OSX của các lệnh này kể từ khi có phiên bản GNU.
Trưởng khoa

@vwvan: Vâng, xin lỗi, bạn sẽ cần GNU sedtrong trường hợp này
Steve

2
@Dean: FWIW, tôi chưa bao giờ muốn chạy OSX :-)
Steve

5
Chỉ cần thay đổi nó sed 's/./\U&/và nó sẽ hoạt động trên POSIX sed.
David Conrad


14

Đây là cách công cụ văn bản "bản địa":

#!/bin/bash

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

cuối cùng là một cái gì đó hoạt động với một biến và trên Mac! Cảm ơn bạn!
OZZIE

4
@DanieleOrlando, không di động như người ta có thể hy vọng. tr [:lower:] [:upper:]là một lựa chọn tốt hơn nếu nó cần hoạt động bằng ngôn ngữ / ngôn ngữ kết hợp các chữ cái không có trong phạm vi a-zhoặc A-Zphạm vi.
Charles Duffy

8

Chỉ sử dụng awk

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

kết quả: Uncapitalized String
Alex Freshmann

4

Nó cũng có thể được thực hiện trong bash thuần với 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}"

Làm thế nào để xác định foo? Tôi đã thử foo = $1nhưng tôi chỉ nhận được-bash: foo: command not found
OZZIE

1
@OZZIE, không có khoảng trống xung quanh =bài tập. Đây là thứ mà shellcheck.net sẽ tìm cho bạn theo chương trình.
Charles Duffy

Tôi luôn quên rằng về các kịch bản shell .. chỉ ngôn ngữ trong đó một không gian (trước / sau) có vấn đề ... thở dài (python là ít nhất 4 nếu tôi nhớ chính xác)
OZZIE

@OZZIE, nó vấn đề, bởi vì nếu nó không quan trọng, bạn không thể chuyển =làm đối số cho một chương trình (làm thế nào để biết nếu someprogram =nó đang chạy someprogramhay gán cho một biến có tên someprogram?)
Charles Duffy

3

Điều này cũng hoạt động ...

FooBar=baz

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

=> Baz
FooBar=baz

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

=> bAz
FooBar=baz

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

=> baZ

Và như thế.

Nguồn:

Giới thiệu / Hướng dẫn:


3

Để viết hoa chỉ từ đầu tiên:

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

Ôi hai ba


Để viết hoa mỗi từ trong biến:

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

O ne T wo T hree


(hoạt động trong bash 4+)


foo='one two three'; foo=$(for i in $foo; do echo -n "${i^} "; done) Độ phân giải ngắn hơn cho mỗi từ. foo Bây giờ là "Một Hai Ba"
vr286 16/12/18

2

Giải pháp thay thế và sạch cho cả Linux và OSX, nó cũng có thể được sử dụng với các biến bash

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

trả lại Abc


0

Cái này làm việc cho tôi:

Tìm kiếm tất cả tệp * php trong thư mục hiện tại và thay thế ký tự đầu tiên của mỗi tên tệp thành chữ in hoa:

ví dụ: test.php => Test.php

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

4
Câu hỏi ban đầu là một chuỗi và không tham chiếu đến việc đổi tên tệp.
AndySavage

0

chỉ để cho vui ở đây:

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

Không chính xác những gì được hỏi nhưng khá hữu ích

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

foo=bar
echo $foo
BAR

Và ngược lại

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-low-xc () {v-first-letter-to-low | xclip -selection clipboard}


-7

Điều gì xảy ra nếu ký tự đầu tiên không phải là một chữ cái (mà là một tab, một khoảng trắng và một trích dẫn kép thoát)? Chúng tôi nên kiểm tra nó tốt hơn cho đến khi chúng tôi tìm thấy một lá thư! Vì thế:

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
Hãy viết mã sạch hơn! bạn đang thiếu trích dẫn ở khắp mọi nơi Bạn đang sử dụng cú pháp lỗi thời (backticks); bạn đang sử dụng cú pháp cổ ( $[...]). Bạn đang sử dụng nhiều dấu ngoặc đơn vô dụng. Bạn đang giả sử rằng chuỗi bao gồm các ký tự từ bảng chữ cái Latinh (làm thế nào về các chữ cái có dấu, hoặc các chữ cái trong các bảng chữ cái khác?). Bạn có rất nhiều công việc để kết xuất đoạn trích này có thể sử dụng được! (và vì bạn đang sử dụng regex, bạn cũng có thể sử dụng regex để tìm chữ cái đầu tiên, thay vì vòng lặp).
gniourf_gniourf

6
Tôi nghĩ bạn đã sai. Đó là nhận xét bắt buộc đi kèm với downvote, giải thích tất cả các mẫu sai và quan niệm sai về câu trả lời. Xin vui lòng, học hỏi từ những sai lầm của bạn (và trước đó, cố gắng hiểu chúng) thay vì bướng bỉnh. Trở thành một đồng nghiệp tốt cũng không tương thích với việc truyền bá các thực hành xấu.
gniourf_gniourf

1
Hoặc, nếu sử dụng Bash 4, bạn không cần tr:if [[ $S =~ ^([^[:alpha:]]*)([[:alpha:]].*) ]]; then out=${BASH_REMATCH[1]}${BASH_REMATCH[2]^}; else out=$S; fi; printf '%s\n' "$out"
gniourf_gniourf

5
Mã này vẫn bị hỏng nặng. Nó vẫn đang sử dụng backticks thay vì cú pháp thay thế hiện đại; nó vẫn có những trích dẫn chưa từng có; nó vẫn còn thiếu dấu ngoặc kép ở những nơi họ làm trong thực tế ; v.v ... Hãy thử đặt một số ký tự toàn cầu bao quanh khoảng trắng vào dữ liệu thử nghiệm của bạn, nếu bạn không tin rằng các trích dẫn bị thiếu đó tạo ra sự khác biệt và khắc phục các sự cố mà shellcheck.net tìm thấy cho đến khi mã này xuất hiện.
Charles Duffy

2
Đối với ngôn ngữ bạn đã trích dẫn từ unix.stackexchange.com/questions/68694/ , điều bạn bỏ lỡ echo $foolà một ví dụ về tình huống mà trình phân tích cú pháp mong đợi một danh sách các từ ; vì vậy echo ${F}, trong nội dung của bạn , Fphân chia chuỗi và mở rộng toàn cầu. Điều đó tương tự đúng với echo ${S:$N:1}ví dụ và tất cả phần còn lại. Xem BashPit thác # 14 .
Charles Duffy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.