Làm thế nào để chuyển đổi một chuỗi thành chữ thường trong Bash?


Câu trả lời:


2181

Có nhiều cách khác nhau:

Tiêu chuẩn POSIX

tr

$ echo "$a" | tr '[:upper:]' '[:lower:]'
hi all

AWK

$ echo "$a" | awk '{print tolower($0)}'
hi all

Không POSIX

Bạn có thể gặp phải các vấn đề về tính di động với các ví dụ sau:

Bash 4.0

$ echo "${a,,}"
hi all

quyến rũ

$ echo "$a" | sed -e 's/\(.*\)/\L\1/'
hi all
# this also works:
$ sed -e 's/\(.*\)/\L\1/' <<< "$a"
hi all

Perl

$ echo "$a" | perl -ne 'print lc'
hi all

Bash

lc(){
    case "$1" in
        [A-Z])
        n=$(printf "%d" "'$1")
        n=$((n+32))
        printf \\$(printf "%o" "$n")
        ;;
        *)
        printf "%s" "$1"
        ;;
    esac
}
word="I Love Bash"
for((i=0;i<${#word};i++))
do
    ch="${word:$i:1}"
    lc "$ch"
done

Lưu ý: YMMV trên cái này. Không hoạt động đối với tôi (GNU bash phiên bản 4.2.46 và 4.0.33 (và hành vi tương tự 2.05b.0 nhưng nocasematch không được triển khai)) ngay cả khi sử dụng shopt -u nocasematch;. Bỏ đặt rằng nocasematch gây ra [["fooBaR" == "FOObar"]] khớp với NHƯNG trong trường hợp kỳ lạ [bz] được khớp không chính xác bởi [AZ]. Bash bị nhầm lẫn bởi tiêu cực kép ("unet nocasematch")! :-)


9
Tôi có thiếu một cái gì đó không, hay ví dụ cuối cùng của bạn (trong Bash) thực sự làm một cái gì đó hoàn toàn khác? Nó hoạt động cho "ABX", nhưng nếu bạn thực hiện word="Hi All"như các ví dụ khác, nó sẽ trả về ha, không hi all. Nó chỉ hoạt động cho các chữ cái viết hoa và bỏ qua các chữ cái đã được hạ thấp.
jangosteve

26
Lưu ý rằng chỉ có các ví dụ trawkđược chỉ định trong tiêu chuẩn POSIX.
Richard Hansen

178
tr '[:upper:]' '[:lower:]'sẽ sử dụng ngôn ngữ hiện tại để xác định chữ hoa / chữ thường, do đó, nó sẽ hoạt động với các ngôn ngữ sử dụng các chữ cái có dấu phụ.
Richard Hansen

10
Làm thế nào để có được đầu ra vào một biến mới? Tức là tôi muốn chuỗi hạ lưu thành một biến mới?
Adam Parkin

60
@Adam:b="$(echo $a | tr '[A-Z]' '[a-z]')"
Tino

435

Trong Bash 4:

Để viết thường

$ string="A FEW WORDS"
$ echo "${string,}"
a FEW WORDS
$ echo "${string,,}"
a few words
$ echo "${string,,[AEIUO]}"
a FeW WoRDS

$ string="A Few Words"
$ declare -l string
$ string=$string; echo "$string"
a few words

Đến trường hợp trên

$ string="a few words"
$ echo "${string^}"
A few words
$ echo "${string^^}"
A FEW WORDS
$ echo "${string^^[aeiou]}"
A fEw wOrds

$ string="A Few Words"
$ declare -u string
$ string=$string; echo "$string"
A FEW WORDS

Chuyển đổi (không có giấy tờ, nhưng có thể cấu hình tùy chọn tại thời điểm biên dịch)

$ string="A Few Words"
$ echo "${string~~}"
a fEW wORDS
$ string="A FEW WORDS"
$ echo "${string~}"
a FEW WORDS
$ string="a few words"
$ echo "${string~}"
A few words

Viết hoa (không có giấy tờ, nhưng có thể cấu hình tùy chọn tại thời điểm biên dịch)

$ string="a few words"
$ declare -c string
$ string=$string
$ echo "$string"
A few words

Trường hợp tiêu đề:

$ string="a few words"
$ string=($string)
$ string="${string[@]^}"
$ echo "$string"
A Few Words

$ declare -c string
$ string=(a few words)
$ echo "${string[@]}"
A Few Words

$ string="a FeW WOrdS"
$ string=${string,,}
$ string=${string~}
$ echo "$string"
A few words

Để tắt một declarethuộc tính, sử dụng +. Ví dụ , declare +c string. Điều này ảnh hưởng đến các bài tập tiếp theo và không phải giá trị hiện tại.

Các declaretùy chọn thay đổi thuộc tính của biến, nhưng không thay đổi nội dung. Việc đánh giá lại trong các ví dụ của tôi cập nhật nội dung để hiển thị các thay đổi.

Biên tập:

Đã thêm "chuyển đổi ký tự đầu tiên bằng từ" ( ${var~}) theo đề xuất của ghostdog74 .

Chỉnh sửa: Sửa hành vi dấu ngã để khớp với Bash 4.3.


5
Các toán tử khá bizzare, "^^" và ",," không hoạt động trên các ký tự không phải ASCII nhưng "~ ~" không ... Vì vậy, string="łódź"; echo ${string~~}sẽ trả về "ŁÓDŹ", nhưng echo ${string^^}trả về "łóDź". Ngay cả trong LC_ALL=pl_PL.utf-8. Đó là sử dụng bash 4.2.24.
Hubert Kario

2
@HubertKario: Thật lạ. Nó giống với tôi trong Bash 4.0.33 với cùng một chuỗi en_US.UTF-8. Đó là một lỗi và tôi đã báo cáo nó.
Tạm dừng cho đến khi có thông báo mới.

1
@HubertKario: Hãy thử echo "$string" | tr '[:lower:]' '[:upper:]'. Nó có thể sẽ thể hiện sự thất bại tương tự. Vì vậy, vấn đề ít nhất là một phần không phải của Bash.
Tạm dừng cho đến khi có thông báo mới.

1
@DennisWilliamson: Vâng, tôi cũng nhận thấy điều đó (xem bình luận cho câu trả lời của Shuvalov). Tôi chỉ nói, "công cụ này chỉ dành cho ASCII", nhưng sau đó, nó là toán tử "~ ~" hoạt động, vì vậy nó không giống như bảng mã và bản dịch chưa có ở đó ...
Hubert Kario

4
@HubertKario: Nhà bảo trì Bash đã thừa nhận lỗi và tuyên bố rằng nó sẽ được sửa trong bản phát hành tiếp theo.
Tạm dừng cho đến khi có thông báo mới.

123
echo "Hi All" | tr "[:upper:]" "[:lower:]"

4
@RichardHansen: trkhông hoạt động đối với tôi đối với các nhân vật không phải ACII. Tôi có tập tin miền địa phương chính xác và tập tin miền địa phương được tạo. Có ai biết tôi có thể làm gì sai không?
Hubert Kario

FYI: Điều này hoạt động trên Windows / Msys. Một số gợi ý khác thì không.
wasatchwizard

3
Tại sao [:upper:]cần thiết?
mgutt

77

tr :

a="$(tr [A-Z] [a-z] <<< "$a")"

GIẢI THƯỞNG :

{ print tolower($0) }

sed :

y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/

2
+1 có a="$(tr [A-Z] [a-z] <<< "$a")"vẻ dễ nhất đối với tôi. Tôi vẫn là người mới bắt đầu ...
Sandeepan Nath

2
Tôi đề nghị sedgiải pháp; Tôi đã làm việc trong một môi trường mà vì một số lý do không có trnhưng tôi vẫn chưa tìm thấy một hệ thống mà không có sed, cộng với rất nhiều thời gian tôi muốn làm điều này Tôi đã làm một cái gì đó khác bằng sedmọi cách để có thể xâu chuỗi các lệnh cùng nhau thành một câu lệnh (dài).
Harastak

2
Các biểu thức khung nên được trích dẫn. Trong tr [A-Z] [a-z] A, shell có thể thực hiện mở rộng tên tệp nếu có tên tệp bao gồm một chữ cái hoặc nullgob được đặt. tr "[A-Z]" "[a-z]" Asẽ cư xử đúng mực.
Dennis

2
@CamiloMartin là hệ thống BusyBox, nơi tôi đang gặp vấn đề đó, cụ thể là NAS Synology, nhưng tôi cũng gặp phải nó trên một vài hệ thống khác. Gần đây tôi đã thực hiện rất nhiều kịch bản shell đa nền tảng, và với yêu cầu không có gì thêm được cài đặt, nó làm cho mọi thứ trở nên rất khó khăn! Tuy nhiên, tôi vẫn chưa gặp phải một hệ thống mà không cósed
Harastak

2
Lưu ý rằng tr [A-Z] [a-z]không chính xác ở hầu hết các địa phương. ví dụ, trong en-USmiền địa phương, A-Zthực sự là khoảng AaBbCcDdEeFfGgHh...XxYyZ.
fuz

44

Tôi biết đây là một bài viết cũ nhưng tôi đã đưa ra câu trả lời này cho một trang web khác vì vậy tôi nghĩ rằng tôi đã đăng nó lên đây:

LỚN -> thấp hơn : sử dụng python:

b=`echo "print '$a'.lower()" | python`

Hoặc Ruby:

b=`echo "print '$a'.downcase" | ruby`

Hoặc Perl (có lẽ là sở thích của tôi):

b=`perl -e "print lc('$a');"`

Hoặc PHP:

b=`php -r "print strtolower('$a');"`

Hoặc Awk:

b=`echo "$a" | awk '{ print tolower($1) }'`

Hoặc Sed:

b=`echo "$a" | sed 's/./\L&/g'`

Hoặc Bash 4:

b=${a,,}

Hoặc NodeJS nếu bạn có nó (và có một chút hạt dẻ ...):

b=`echo "console.log('$a'.toLowerCase());" | node`

Bạn cũng có thể sử dụng dd(nhưng tôi sẽ không!):

b=`echo "$a" | dd  conv=lcase 2> /dev/null`

thấp hơn -> LỚN :

sử dụng trăn:

b=`echo "print '$a'.upper()" | python`

Hoặc Ruby:

b=`echo "print '$a'.upcase" | ruby`

Hoặc Perl (có lẽ là sở thích của tôi):

b=`perl -e "print uc('$a');"`

Hoặc PHP:

b=`php -r "print strtoupper('$a');"`

Hoặc Awk:

b=`echo "$a" | awk '{ print toupper($1) }'`

Hoặc Sed:

b=`echo "$a" | sed 's/./\U&/g'`

Hoặc Bash 4:

b=${a^^}

Hoặc NodeJS nếu bạn có nó (và có một chút hạt dẻ ...):

b=`echo "console.log('$a'.toUpperCase());" | node`

Bạn cũng có thể sử dụng dd(nhưng tôi sẽ không!):

b=`echo "$a" | dd  conv=ucase 2> /dev/null`

Ngoài ra khi bạn nói 'shell' tôi giả sử bạn có ý bashnhưng nếu bạn có thể sử dụng zshnó dễ như

b=$a:l

cho chữ thường và

b=$a:u

cho chữ hoa


@JESii cả hai đều làm việc cho tôi trên -> dưới và dưới-> trên. Tôi đang sử dụng sed 4.2.2 và Bash 4.3.42 (1) trên Debian Stretch 64 bit.
nettux

1
Xin chào, @ nettux443 ... Tôi vừa thử lại thao tác bash và nó vẫn thất bại với thông báo lỗi "thay thế xấu". Tôi đang dùng OSX bằng cách sử dụng bash của homebrew: GNU bash, phiên bản 4.3.42 (1) -release (x86_64-apple-darwin14.5.0)
JESii

5
Không được dùng! Tất cả các ví dụ tạo ra một kịch bản là cực kỳ dễ vỡ; nếu giá trị achứa một trích dẫn, bạn không chỉ có hành vi bị hỏng mà còn gặp sự cố bảo mật nghiêm trọng.
tripleee

Tôi thích giải pháp sed nhất, vì sed luôn có mặt khắp nơi.
Cậu bé Dudi

Tôi thích sử dụng các giải pháp dd. Xin lưu ý rằng bạn cần phải root để hoạt động
inetph Phantom


18

Sử dụng GNU sed:

sed 's/.*/\L&/'

Thí dụ:

$ foo="Some STRIng";
$ foo=$(echo "$foo" | sed 's/.*/\L&/')
$ echo "$foo"
some string

12

Tiền Bash 4.0

Bash Hạ trường hợp của một chuỗi và gán cho biến

VARIABLE=$(echo "$VARIABLE" | tr '[:upper:]' '[:lower:]') 

echo "$VARIABLE"

5
Không cần echovà đường ống: sử dụng$(tr '[:upper:]' '[:lower:]' <<<"$VARIABLE")
Tino

3
@Tino Chuỗi ở đây cũng không thể quay lại các phiên bản thực sự cũ của Bash; Tôi tin rằng nó đã được giới thiệu trong v3.
tripleee

1
@tripleee Bạn nói đúng, nó được giới thiệu trong bash-2.05b - tuy nhiên đó là bash lâu đời nhất tôi có thể tìm thấy trên các hệ thống của mình
Tino

11

Đối với hệ vỏ tiêu chuẩn (không có bashism) chỉ sử dụng nội dung:

uppers=ABCDEFGHIJKLMNOPQRSTUVWXYZ
lowers=abcdefghijklmnopqrstuvwxyz

lc(){ #usage: lc "SOME STRING" -> "some string"
    i=0
    while ([ $i -lt ${#1} ]) do
        CUR=${1:$i:1}
        case $uppers in
            *$CUR*)CUR=${uppers%$CUR*};OUTPUT="${OUTPUT}${lowers:${#CUR}:1}";;
            *)OUTPUT="${OUTPUT}$CUR";;
        esac
        i=$((i+1))
    done
    echo "${OUTPUT}"
}

Và cho chữ hoa:

uc(){ #usage: uc "some string" -> "SOME STRING"
    i=0
    while ([ $i -lt ${#1} ]) do
        CUR=${1:$i:1}
        case $lowers in
            *$CUR*)CUR=${lowers%$CUR*};OUTPUT="${OUTPUT}${uppers:${#CUR}:1}";;
            *)OUTPUT="${OUTPUT}$CUR";;
        esac
        i=$((i+1))
    done
    echo "${OUTPUT}"
}

Tôi tự hỏi nếu bạn đã không để một số bashism trong kịch bản này, vì nó không phải là di động trên FreeBSD sh: $ {1: $ ...}: Xấu thay
Dereckson

2
Thật; các chuỗi con ${var:1:1}là một Bashism.
tripleee

Cách tiếp cận này có số liệu hiệu suất khá xấu. Xem câu trả lời của tôi cho số liệu.
Dejay Clayton

9

Trong bash 4, bạn có thể sử dụng sắp chữ

Thí dụ:

A="HELLO WORLD"
typeset -l A=$A


7

Biểu hiện thông thường

Tôi muốn nhận tín dụng cho lệnh tôi muốn chia sẻ nhưng sự thật là tôi đã nhận được nó để sử dụng từ http://commandlinefu.com . Nó có lợi thế là nếu bạn cdvào bất kỳ thư mục nào trong thư mục nhà riêng của mình, nó sẽ thay đổi tất cả các tệp và thư mục thành chữ thường, vui lòng sử dụng một cách thận trọng. Đây là một sửa lỗi dòng lệnh tuyệt vời và đặc biệt hữu ích cho vô số album bạn đã lưu trữ trên ổ đĩa của bạn.

find . -depth -exec rename 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \;

Bạn có thể chỉ định một thư mục thay cho dấu chấm (.) Sau khi tìm thấy biểu thị thư mục hiện tại hoặc đường dẫn đầy đủ.

Tôi hy vọng giải pháp này chứng minh hữu ích một điều mà lệnh này không làm là thay thế khoảng trắng bằng dấu gạch dưới - có lẽ một lần khác có lẽ.


Điều này không làm việc cho tôi vì bất cứ lý do gì, mặc dù nó có vẻ tốt. Tôi đã làm điều này để làm việc thay thế mặc dù: tìm. -exec / bin / bash -c 'mv {} `tr [AZ] [az] <<< {}`' \;
John Rix

Điều này cần prenametừ perl: dpkg -S "$(readlink -e /usr/bin/rename)"choperl: /usr/bin/prename
Tino

4

Nhiều câu trả lời sử dụng các chương trình bên ngoài, mà không thực sự sử dụng Bash.

Nếu bạn biết bạn sẽ có sẵn Bash4, bạn thực sự chỉ nên sử dụng ${VAR,,}ký hiệu (nó rất dễ dàng và tuyệt vời). Đối với Bash trước 4 (Mac của tôi vẫn sử dụng Bash 3.2 chẳng hạn). Tôi đã sử dụng phiên bản sửa của câu trả lời của @ ghostdog74 để tạo phiên bản di động hơn.

Một bạn có thể gọi lowercase 'my STRING'và nhận được một phiên bản chữ thường. Tôi đọc các bình luận về việc đặt kết quả thành một var, nhưng điều đó không thực sự di động Bash, vì chúng tôi không thể trả về chuỗi. In nó là giải pháp tốt nhất. Dễ dàng chụp với một cái gì đó như var="$(lowercase $str)".

Làm thế nào điều này hoạt động

Cách thức này hoạt động là bằng cách lấy đại diện số nguyên ASCII của mỗi char với printfvà sau đó adding 32nếu upper-to->lower, hoặc subtracting 32nếu lower-to->upper. Sau đó sử dụng printflại để chuyển đổi số trở lại thành char. Từ 'A' -to-> 'a'chúng tôi có một sự khác biệt của 32 ký tự.

Sử dụng printfđể giải thích:

$ printf "%d\n" "'a"
97
$ printf "%d\n" "'A"
65

97 - 65 = 32

Và đây là phiên bản làm việc với các ví dụ.
Xin lưu ý các ý kiến ​​trong mã, vì chúng giải thích rất nhiều thứ:

#!/bin/bash

# lowerupper.sh

# Prints the lowercase version of a char
lowercaseChar(){
    case "$1" in
        [A-Z])
            n=$(printf "%d" "'$1")
            n=$((n+32))
            printf \\$(printf "%o" "$n")
            ;;
        *)
            printf "%s" "$1"
            ;;
    esac
}

# Prints the lowercase version of a sequence of strings
lowercase() {
    word="$@"
    for((i=0;i<${#word};i++)); do
        ch="${word:$i:1}"
        lowercaseChar "$ch"
    done
}

# Prints the uppercase version of a char
uppercaseChar(){
    case "$1" in
        [a-z])
            n=$(printf "%d" "'$1")
            n=$((n-32))
            printf \\$(printf "%o" "$n")
            ;;
        *)
            printf "%s" "$1"
            ;;
    esac
}

# Prints the uppercase version of a sequence of strings
uppercase() {
    word="$@"
    for((i=0;i<${#word};i++)); do
        ch="${word:$i:1}"
        uppercaseChar "$ch"
    done
}

# The functions will not add a new line, so use echo or
# append it if you want a new line after printing

# Printing stuff directly
lowercase "I AM the Walrus!"$'\n'
uppercase "I AM the Walrus!"$'\n'

echo "----------"

# Printing a var
str="A StRing WITH mixed sTUFF!"
lowercase "$str"$'\n'
uppercase "$str"$'\n'

echo "----------"

# Not quoting the var should also work, 
# since we use "$@" inside the functions
lowercase $str$'\n'
uppercase $str$'\n'

echo "----------"

# Assigning to a var
myLowerVar="$(lowercase $str)"
myUpperVar="$(uppercase $str)"
echo "myLowerVar: $myLowerVar"
echo "myUpperVar: $myUpperVar"

echo "----------"

# You can even do stuff like
if [[ 'option 2' = "$(lowercase 'OPTION 2')" ]]; then
    echo "Fine! All the same!"
else
    echo "Ops! Not the same!"
fi

exit 0

Và kết quả sau khi chạy này:

$ ./lowerupper.sh 
i am the walrus!
I AM THE WALRUS!
----------
a string with mixed stuff!
A STRING WITH MIXED STUFF!
----------
a string with mixed stuff!
A STRING WITH MIXED STUFF!
----------
myLowerVar: a string with mixed stuff!
myUpperVar: A STRING WITH MIXED STUFF!
----------
Fine! All the same!

Điều này chỉ nên làm việc cho các ký tự ASCII .

Đối với tôi điều đó là tốt, vì tôi biết tôi sẽ chỉ truyền ký tự ASCII cho nó.
Tôi đang sử dụng điều này cho một số tùy chọn CLI không phân biệt chữ hoa chữ thường.


4

Trường hợp chuyển đổi được thực hiện cho chỉ bảng chữ cái. Vì vậy, điều này nên làm việc gọn gàng.

Tôi đang tập trung vào việc chuyển đổi bảng chữ cái giữa az từ chữ hoa sang chữ thường. Bất kỳ ký tự nào khác chỉ nên được in ở thiết bị xuất chuẩn vì nó là ...

Chuyển đổi tất cả văn bản trong đường dẫn / thành / tệp / tên tệp trong phạm vi az thành AZ

Để chuyển đổi chữ thường thành chữ hoa

cat path/to/file/filename | tr 'a-z' 'A-Z'

Để chuyển đổi từ chữ hoa sang chữ thường

cat path/to/file/filename | tr 'A-Z' 'a-z'

Ví dụ,

tên tệp:

my name is xyz

được chuyển đổi thành:

MY NAME IS XYZ

Ví dụ 2:

echo "my name is 123 karthik" | tr 'a-z' 'A-Z'
# Output:
# MY NAME IS 123 KARTHIK

Ví dụ 3:

echo "my name is 123 &&^&& #@$#@%%& kAR2~thik" | tr 'a-z' 'A-Z'
# Output:
# MY NAME IS 123 &&^&& #@0@%%& KAR2~THIK

3

Nếu sử dụng v4, đây là nướng trong . Nếu không, đây là một giải pháp đơn giản, áp dụng rộng rãi . Các câu trả lời khác (và nhận xét) về chủ đề này khá hữu ích trong việc tạo mã bên dưới.

# Like echo, but converts to lowercase
echolcase () {
    tr [:upper:] [:lower:] <<< "${*}"
}

# Takes one arg by reference (var name) and makes it lowercase
lcase () { 
    eval "${1}"=\'$(echo ${!1//\'/"'\''"} | tr [:upper:] [:lower:] )\'
}

Ghi chú:

  • Làm: a="Hi All"và sau đó: lcase asẽ làm điều tương tự như:a=$( echolcase "Hi All" )
  • Trong hàm lcase, sử dụng ${!1//\'/"'\''"}thay vì ${!1}cho phép điều này hoạt động ngay cả khi chuỗi có dấu ngoặc kép.

3

Đối với các phiên bản Bash sớm hơn 4.0, phiên bản này phải nhanh nhất (vì nó không rẽ nhánh / thực thi bất kỳ lệnh nào):

function string.monolithic.tolower
{
   local __word=$1
   local __len=${#__word}
   local __char
   local __octal
   local __decimal
   local __result

   for (( i=0; i<__len; i++ ))
   do
      __char=${__word:$i:1}
      case "$__char" in
         [A-Z] )
            printf -v __decimal '%d' "'$__char"
            printf -v __octal '%03o' $(( $__decimal ^ 0x20 ))
            printf -v __char \\$__octal
            ;;
      esac
      __result+="$__char"
   done
   REPLY="$__result"
}

Câu trả lời của Technosaurus cũng có tiềm năng, mặc dù nó đã chạy đúng cho mee.


Không tệ! Để biết phân tích về hiệu suất của phương pháp này, vui lòng xem câu trả lời của tôi cho các số liệu.
Dejay Clayton

3

Mặc dù câu hỏi này bao nhiêu tuổi và tương tự như câu trả lời này của Technosaurus . Tôi đã có một thời gian khó khăn để tìm một giải pháp di động trên hầu hết các nền tảng (That I Use) cũng như các phiên bản bash cũ hơn. Tôi cũng đã thất vọng với các mảng, chức năng và sử dụng các bản in, tiếng vang và các tập tin tạm thời để lấy các biến tầm thường. Điều này làm việc rất tốt cho tôi cho đến nay tôi nghĩ rằng tôi sẽ chia sẻ. Môi trường thử nghiệm chính của tôi là:

  1. GNU bash, phiên bản 4.1.2 (1) -release (x86_64-redhat-linux-gnu)
  2. GNU bash, phiên bản 3.2.57 (1) -release (sparc-sun-solaris2.10)
lcs="abcdefghijklmnopqrstuvwxyz"
ucs="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
input="Change Me To All Capitals"
for (( i=0; i<"${#input}"; i++ )) ; do :
    for (( j=0; j<"${#lcs}"; j++ )) ; do :
        if [[ "${input:$i:1}" == "${lcs:$j:1}" ]] ; then
            input="${input/${input:$i:1}/${ucs:$j:1}}" 
        fi
    done
done

Kiểu C đơn giản cho vòng lặp để lặp qua các chuỗi. Đối với dòng dưới đây nếu bạn chưa thấy bất cứ điều gì như thế này trước đây là nơi tôi đã học được điều này . Trong trường hợp này, dòng kiểm tra xem char $ {input: $ i: 1} (chữ thường) có tồn tại trong đầu vào không và nếu có thì thay thế nó bằng char $ {ucs: $ j: 1} (chữ hoa) và lưu trữ nó trở lại đầu vào.

input="${input/${input:$i:1}/${ucs:$j:1}}"

Điều này cực kỳ không hiệu quả, lặp lại 650 lần trong ví dụ của bạn ở trên và mất 35 giây để thực hiện 1000 yêu cầu trên máy của tôi. Đối với một giải pháp thay thế chỉ vòng 11 lần và mất ít hơn 5 giây để thực hiện 1000 lệnh, hãy xem câu trả lời thay thế của tôi.
Dejay Clayton

1
Cảm ơn, mặc dù điều đó nên rõ ràng chỉ từ việc nhìn vào nó. Có lẽ lỗi trang là từ kích thước đầu vào và số lần lặp bạn đang thực hiện. Tuy nhiên tôi thích giải pháp của bạn.
JaredTS486

3

Đây là một biến thể nhanh hơn nhiều của cách tiếp cận của JaredTS486 , sử dụng các khả năng Bash gốc (bao gồm các phiên bản Bash <4.0) để tối ưu hóa cách tiếp cận của anh ta.

Tôi đã hẹn giờ 1.000 lần lặp của phương pháp này cho một chuỗi nhỏ (25 ký tự) và một chuỗi lớn hơn (445 ký tự), cho cả chuyển đổi chữ thường và chữ hoa. Vì các chuỗi kiểm tra chủ yếu là chữ thường, chuyển đổi sang chữ thường thường nhanh hơn chữ hoa.

Tôi đã so sánh cách tiếp cận của mình với một số câu trả lời khác trên trang này tương thích với Bash 3.2. Cách tiếp cận của tôi hiệu quả hơn nhiều so với hầu hết các cách tiếp cận được ghi lại ở đây, và thậm chí còn nhanh hơn trtrong một số trường hợp.

Dưới đây là kết quả thời gian cho 1.000 lần lặp gồm 25 ký tự:

Kết quả thời gian cho 1.000 lần lặp của 445 ký tự (bao gồm bài thơ "The Robin" của Witter Bynner):

  • 2s cho cách tiếp cận chữ thường của tôi; 12s cho chữ hoa
  • 4s cho trchữ thường; 4s cho chữ hoa
  • 20s cho cách tiếp cận chữ thường của Orwellophile ; 29s cho chữ hoa
  • 75 hiện cho ghostdog74 của cách tiếp cận để chữ thường; 669s cho chữ hoa. Thật thú vị khi lưu ý sự khác biệt về hiệu suất giữa một bài kiểm tra với các trận đấu chiếm ưu thế so với một bài kiểm tra với các lỗi chiếm ưu thế
  • 467s cho cách tiếp cận chữ thường của Technosaurus ; 449s cho chữ hoa
  • 660 cho cách tiếp cận chữ thường của JaredTS486 ; 660s cho chữ hoa. Thật thú vị khi lưu ý rằng cách tiếp cận này tạo ra lỗi trang liên tục (hoán đổi bộ nhớ) trong Bash

Giải pháp:

#!/bin/bash
set -e
set -u

declare LCS="abcdefghijklmnopqrstuvwxyz"
declare UCS="ABCDEFGHIJKLMNOPQRSTUVWXYZ"

function lcase()
{
  local TARGET="${1-}"
  local UCHAR=''
  local UOFFSET=''

  while [[ "${TARGET}" =~ ([A-Z]) ]]
  do
    UCHAR="${BASH_REMATCH[1]}"
    UOFFSET="${UCS%%${UCHAR}*}"
    TARGET="${TARGET//${UCHAR}/${LCS:${#UOFFSET}:1}}"
  done

  echo -n "${TARGET}"
}

function ucase()
{
  local TARGET="${1-}"
  local LCHAR=''
  local LOFFSET=''

  while [[ "${TARGET}" =~ ([a-z]) ]]
  do
    LCHAR="${BASH_REMATCH[1]}"
    LOFFSET="${LCS%%${LCHAR}*}"
    TARGET="${TARGET//${LCHAR}/${UCS:${#LOFFSET}:1}}"
  done

  echo -n "${TARGET}"
}

Cách tiếp cận rất đơn giản: trong khi chuỗi đầu vào có bất kỳ chữ cái in hoa nào còn lại, hãy tìm cái tiếp theo và thay thế tất cả các trường hợp của chữ cái đó bằng biến thể chữ thường của nó. Lặp lại cho đến khi tất cả các chữ cái viết hoa được thay thế.

Một số đặc điểm hiệu suất của giải pháp của tôi:

  1. Chỉ sử dụng các tiện ích dựng sẵn shell, giúp tránh chi phí cho việc gọi các tiện ích nhị phân bên ngoài trong một quy trình mới
  2. Tránh các vỏ phụ, chịu các hình phạt về hiệu suất
  3. Sử dụng các cơ chế shell được biên dịch và tối ưu hóa cho hiệu suất, chẳng hạn như thay thế chuỗi toàn cầu trong các biến, cắt hậu tố biến, và tìm kiếm và kết hợp regex. Các cơ chế này nhanh hơn nhiều so với việc lặp thủ công thông qua các chuỗi
  4. Vòng lặp chỉ số lần yêu cầu của số lượng ký tự khớp duy nhất được chuyển đổi. Ví dụ: chuyển đổi một chuỗi có ba ký tự viết hoa khác nhau thành chữ thường chỉ cần 3 lần lặp. Đối với bảng chữ cái ASCII được cấu hình sẵn, số lần lặp tối đa là 26
  5. UCSLCScó thể được tăng thêm với các ký tự bổ sung

2

Để lưu trữ chuỗi biến đổi thành một biến. Sau đây làm việc cho tôi - $SOURCE_NAMEđể$TARGET_NAME

TARGET_NAME="`echo $SOURCE_NAME | tr '[:upper:]' '[:lower:]'`"

1

Cách đơn giản

echo "Hi all" | awk '{ print tolower($0); }'
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.