tra-loi-cau-hoi-phat-trien-web.com

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

Có cách nào trong bash để chuyển đổi một chuỗi thành một chuỗi chữ thường không?

Ví dụ: nếu tôi có:

a="Hi all"

Tôi muốn chuyển đổi nó thành:

"hi all"
1008
assassin

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

sed

$ 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
1779
ghostdog74

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 thuộc tính declare, hãy 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 tùy chọn declare 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.

Chỉnh sửa:

Đã thêm "chuyển đổi ký tự đầu tiên bằng Word" (${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.

383
Dennis Williamson
echo "Hi All" | tr "[:upper:]" "[:lower:]"
116
shuvalov

tr :

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

AWK :

{ print tolower($0) }

sed :

y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
72

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ó nghĩa là bash nhưng nếu bạn có thể sử dụng zsh thì dễ như

b=$a:l

cho chữ thường và

b=$a:u

cho chữ hoa.

38
nettux

Trong zsh:

echo $a:u

Phải yêu zsh!

26
Scott Smedley

Sử dụng GNU sed:

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

Thí dụ:

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

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

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}"
}
11
technosaurus

Tiền Bash 4.0

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

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

echo "$VARIABLE"
10
hawkeye126

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

Thí dụ:

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

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 cho riêng mình từ http://commandlinefu.com . Nó có lợi thế là nếu bạn cd vào bất kỳ thư mục nào trong thư mục nhà riêng của bạn, 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. Nó là một sửa chữa 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ẽ.

7
Derek Shaw

Bạn có thể thử cái này

s="Hello World!" 

echo $s  # Hello World!

a=${s,,}
echo $a  # hello world!

b=${s^^}
echo $b  # HELLO WORLD!

enter image description here

ref: http://wiki.workrame.com/Shell-script-convert-text-to-lowercase-and-uppercase/

6
Bikesh M Annur

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, echos và các tập tin tạm thời để lấy các biến tầm thường. Điều này hoạt động rất tốt đối với 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

Đơn giản Kiểu chữ C cho vòng lặp để lặp qua các chuỗi . Đối với dòng bên dưới nếu bạn chưa thấy bất cứ điều gì như thế này trước đây đâ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}}"
3
JaredTS486

Đố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 fork/exec 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.

3
Orwellophile

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ú:

  • Thực hiện: a="Hi All" và sau đó: lcase a sẽ 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
Stephen M. Harris

Nhiều câu trả lời sử dụng các chương trình bên ngoài, 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 ký hiệu ${VAR,,} (thật dễ dàng và thú vị). Đố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 phiên bản chữ thường. Tôi đã đọc các nhận xét về việc đặt kết quả thành một var, nhưng điều đó không thực sự khả chuyển trong 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)"

Cách thức hoạt động

Cách thức hoạt động này là bằng cách lấy đại diện số nguyên ASCII của mỗi char với printf và sau đó adding 32 nếu upper-to->lower hoặc subtracting 32 nếu lower-to->upper. Sau đó sử dụng printf một lần nữa để chuyển đổi số trở lại thành char. Từ 'A' -to-> 'a' chúng ta có chênh lệch 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="[email protected]"
    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="[email protected]"
    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 "[email protected]" 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ỉ hoạt động đối với các ký tự ASCII

Đối với tôi điều đó là tốt, vì tôi biết tôi sẽ chỉ chuyển ASCII ký tự 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.

3
Gus Neves

Nếu bạn thích python và có tùy chọn cài đặt gói python mới, bạn có thể thử tiện ích python này .

# install pythonp
$ pip install pythonp

$ echo $a | pythonp "l.lower()"
2
bombs

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 a-z 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 a-z thành A-Z

Để 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 &&^&& #@[email protected]%%& KAR2~THIK
1
theBuzzyCoder

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

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

Đâ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 phương pháp của mình.

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 tr trong 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 tr thành chữ thường; 4s cho chữ hoa
  • 20 giây cho Cách tiếp cận của Orwellophile để viết thường; 29s cho chữ hoa
  • 75 giây cho ghostdog74's 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 thử nghiệm với các trận đấu chiếm ưu thế so với thử nghiệm với các sai sót chiếm ưu thế
  • 46 giây cho phương pháp của Technosaurus để viết thường; 449s cho chữ hoa
  • 660 cho Cách tiếp cận của JaredTS486 để viết thường; 660s cho chữ hoa. Thật thú vị khi lưu ý rằng phương pháp này đã tạo ra các lỗi trang liên tục (hoán đổi bộ nhớ) trong Bash

Dung dịch:

#!/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ụ, trong đó phải 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 lặp tối đa là 26
  5. UCSLCS có thể được tăng thêm bằng các ký tự bổ sung
0
Dejay Clayton