Bagaimana cara mengubah string menjadi huruf kecil di Bash?

Jawaban:

2182

Ada berbagai cara:

Standar POSIX

tr

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

AWK

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

Non-POSIX

Anda dapat mengalami masalah portabilitas dengan contoh-contoh berikut:

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

Pesta

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

Catatan: YMMV yang satu ini. Tidak bekerja untuk saya (GNU bash versi 4.2.46 dan 4.0.33 (dan perilaku yang sama 2.05b.0 tetapi nocasematch tidak diterapkan)) bahkan dengan menggunakan shopt -u nocasematch;. Tidak mengonfirmasi bahwa nocasematch menyebabkan [["fooBaR" == "FOObar"]] cocok dengan OK TAPI di dalam case aneh [bz] tidak cocok dengan [AZ]. Bash bingung oleh double-negative ("unsetting nocasematch")! :-)

ghostdog74
sumber
9
Apakah saya kehilangan sesuatu, atau apakah contoh terakhir Anda (di Bash) benar-benar melakukan sesuatu yang sama sekali berbeda? Ini berfungsi untuk "ABX", tetapi jika Anda membuat word="Hi All"seperti contoh-contoh lain, ia kembali ha, tidak hi all. Ini hanya berfungsi untuk huruf kapital dan melompati huruf yang sudah lebih kecil.
jangosteve
26
Perhatikan bahwa hanya trdan awkcontoh yang ditentukan dalam standar POSIX.
Richard Hansen
178
tr '[:upper:]' '[:lower:]'akan menggunakan lokal saat ini untuk menentukan setara huruf besar / kecil, jadi itu akan berfungsi dengan lokal yang menggunakan huruf dengan tanda diakritik.
Richard Hansen
10
Bagaimana cara mendapatkan output ke variabel baru? Yaitu saya ingin string yang lebih kecil menjadi variabel baru?
Adam Parkin
60
@Adam:b="$(echo $a | tr '[A-Z]' '[a-z]')"
Tino
435

Dalam Bash 4:

Untuk huruf kecil

$ 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

Ke huruf besar

$ 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

Toggle (tidak berdokumen, tetapi dapat dikonfigurasi opsional saat waktu kompilasi)

$ 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

Kapitalisasi (tidak terdokumentasi, tetapi dapat dikonfigurasi secara opsional pada waktu kompilasi)

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

Judul kasus:

$ 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

Untuk mematikan declareatribut, gunakan +. Sebagai contoh declare +c string,. Ini memengaruhi penugasan selanjutnya dan bukan nilai saat ini.

The declarepilihan mengubah atribut dari variabel, tetapi bukan isi. Penugasan kembali dalam contoh saya memperbarui konten untuk menunjukkan perubahan.

Edit:

Menambahkan "beralih karakter pertama dengan kata" ( ${var~}) seperti yang disarankan oleh ghostdog74 .

Sunting: Perilaku tilde yang diperbaiki agar sesuai dengan Bash 4.3.

Dijeda sampai pemberitahuan lebih lanjut.
sumber
5
Cukup aneh, "^^" dan ",," operator tidak bekerja pada karakter non-ASCII tetapi "~~" tidak ... Jadi string="łódź"; echo ${string~~}akan mengembalikan "ŁÓDŹ", tetapi echo ${string^^}mengembalikan "łóDź". Bahkan di LC_ALL=pl_PL.utf-8. Itu menggunakan bash 4.2.24.
Hubert Kario
2
@ HubertKario: Aneh. Ini sama bagi saya di Bash 4.0.33 dengan string yang sama en_US.UTF-8. Ini bug dan saya sudah melaporkannya.
Dijeda sampai pemberitahuan lebih lanjut.
1
@ HubertKario: Coba echo "$string" | tr '[:lower:]' '[:upper:]'. Mungkin akan menunjukkan kegagalan yang sama. Jadi masalahnya setidaknya sebagian bukan milik Bash.
Dijeda sampai pemberitahuan lebih lanjut.
1
@ DennisWilliamson: Ya, saya sudah memperhatikan itu juga (lihat komentar untuk jawaban Shuvalov). Saya hanya akan mengatakan, "barang ini hanya untuk ASCII", tetapi kemudian operator "~~" yang berfungsi, jadi tidak seperti kode dan tabel terjemahan belum ada di sana ...
Hubert Kario
4
@HubertKario: Pemelihara Bash telah mengakui bug dan menyatakan bahwa bug tersebut akan diperbaiki pada rilis berikutnya.
Dijeda sampai pemberitahuan lebih lanjut.
123
echo "Hi All" | tr "[:upper:]" "[:lower:]"
shuvalov
sumber
4
@RichardHansen: trtidak berfungsi untuk saya untuk karakter non-ACII. Saya memiliki set lokal yang benar dan file lokal yang dihasilkan. Ada yang tahu apa yang bisa saya lakukan salah?
Hubert Kario
FYI: Ini berfungsi pada Windows / Msys. Beberapa saran lain tidak.
wasatchwizard
3
Mengapa [:upper:]dibutuhkan?
mgutt
77

tr :

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

AWK :

{ print tolower($0) }

sed :

y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
Ignacio Vazquez-Abrams
sumber
2
+1 a="$(tr [A-Z] [a-z] <<< "$a")"terlihat paling mudah bagi saya. Saya masih pemula ...
Sandeepan Nath
2
Saya sangat merekomendasikan sedsolusinya; Saya telah bekerja di lingkungan yang karena alasan tertentu tidak ada trtetapi saya belum menemukan sistem tanpa sed, ditambah banyak waktu saya ingin melakukan ini, saya hanya melakukan sesuatu yang lain sedsehingga dapat membuat rantai perintah bersama menjadi satu pernyataan (panjang).
Haravikk
2
Ekspresi braket harus dikutip. Dalam tr [A-Z] [a-z] A, shell dapat melakukan ekspansi nama file jika ada nama file yang terdiri dari satu huruf atau nullgob diatur. tr "[A-Z]" "[a-z]" Aakan berperilaku baik.
Dennis
2
@ CamiloMartin ini adalah sistem BusyBox tempat saya mengalami masalah itu, khususnya Synology NASes, tetapi saya juga pernah menemukannya di beberapa sistem lain. Saya telah melakukan banyak skrip shell lintas-platform akhir-akhir ini, dan dengan persyaratan bahwa tidak ada tambahan yang diinstal itu membuat semuanya sangat rumit! Namun saya belum menemukan sistem tanpased
Haravikk
2
Catatan yang tr [A-Z] [a-z]salah di hampir semua lokal. misalnya, di en-USlokal, A-Zsebenarnya adalah intervalnya AaBbCcDdEeFfGgHh...XxYyZ.
fuz
44

Saya tahu ini adalah posting lawas tetapi saya membuat jawaban ini untuk situs lain jadi saya pikir saya akan mempostingnya di sini:

UPPER -> lower : use python:

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

Atau Ruby:

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

Atau Perl (mungkin favorit saya):

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

Atau PHP:

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

Atau Awk:

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

Atau Sed:

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

Atau Bash 4:

b=${a,,}

Atau NodeJS jika Anda memilikinya (dan sedikit gila ...):

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

Anda juga bisa menggunakan dd(tapi saya tidak mau!):

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

lebih rendah -> UPPER :

gunakan python:

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

Atau Ruby:

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

Atau Perl (mungkin favorit saya):

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

Atau PHP:

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

Atau Awk:

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

Atau Sed:

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

Atau Bash 4:

b=${a^^}

Atau NodeJS jika Anda memilikinya (dan sedikit gila ...):

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

Anda juga bisa menggunakan dd(tapi saya tidak mau!):

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

Juga ketika Anda mengatakan 'shell' saya berasumsi maksud Anda bashtetapi jika Anda dapat menggunakannya zshsemudah

b=$a:l

untuk huruf kecil dan

b=$a:u

untuk huruf besar.

nettux
sumber
@ YESUS keduanya bekerja untuk saya atas -> bawah dan bawah-> atas. Saya menggunakan sed 4.2.2 dan Bash 4.3.42 (1) pada 64bit Debian Stretch.
nettux
1
Hai, @ nettux443 ... Saya baru saja mencoba operasi bash lagi dan masih gagal bagi saya dengan pesan kesalahan "substitusi buruk". Saya menggunakan OSX menggunakan bash homebrew: GNU bash, versi 4.3.42 (1) -release (x86_64-apple-darwin14.5.0)
JESii
5
Jangan gunakan! Semua contoh yang menghasilkan skrip sangat rapuh; jika nilai aberisi satu kutipan, Anda tidak hanya merusak perilaku, tetapi juga masalah keamanan yang serius.
tripleee
Saya paling suka solusi sed, karena sed selalu ada di mana-mana.
Dudi Boy
Saya lebih suka menggunakan solusi dd. Harap dicatat bahwa Anda harus menjadi root untuk membuatnya berfungsi
inetphantom
29

Dalam zsh:

echo $a:u

Harus cinta zsh!

Scott Smedley
sumber
4
atau $ a: l untuk konversi huruf kecil
Scott Smedley
1
Tambahkan satu kasus lagi:echo ${(C)a} #Upcase the first char only
biocyberman
18

Menggunakan GNU sed:

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

Contoh:

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

Pre Bash 4.0

Bash Turunkan Kasing dari string dan tetapkan ke variabel

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

echo "$VARIABLE"
hawkeye126
sumber
5
Tidak perlu echodan pipa: gunakan$(tr '[:upper:]' '[:lower:]' <<<"$VARIABLE")
Tino
3
@Tino String di sini juga tidak portabel kembali ke versi Bash yang benar-benar lama; Saya percaya itu diperkenalkan di v3.
tripleee
1
@ tripleee Anda benar, ini diperkenalkan di bash-2.05b - namun itu adalah bash tertua yang dapat saya temukan di sistem saya
Tino
11

Untuk shell standar (tanpa bashisme) hanya menggunakan builtin:

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

Dan untuk huruf besar:

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}"
}
technosaurus
sumber
Saya ingin tahu apakah Anda tidak membiarkan beberapa bashism dalam skrip ini, karena ini tidak portabel di FreeBSD sh: $ {1: $ ...}: Substitusi buruk
Dereckson
2
Memang; substring dengan ${var:1:1}adalah Bashism.
tripleee
Pendekatan ini memiliki metrik kinerja yang sangat buruk. Lihat jawaban saya untuk metrik.
Dejay Clayton
9

Di bash 4 Anda bisa menggunakan setet

Contoh:

A="HELLO WORLD"
typeset -l A=$A
c4f4t0r
sumber
7

Ekspresi reguler

Saya ingin menerima pujian untuk perintah yang ingin saya bagikan tetapi kenyataannya adalah saya mendapatkannya untuk saya gunakan sendiri dari http://commandlinefu.com . Ini memiliki keuntungan bahwa jika Anda cdke direktori mana pun di dalam folder home Anda sendiri, itu akan mengubah semua file dan folder menjadi huruf kecil secara rekursi, silakan gunakan dengan hati-hati. Ini adalah perbaikan baris perintah yang brilian dan sangat berguna untuk banyak album yang telah Anda simpan di drive Anda.

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

Anda bisa menentukan direktori sebagai pengganti titik (.) Setelah menemukan yang menunjukkan direktori saat ini atau path lengkap.

Saya harap solusi ini terbukti bermanfaat. Satu hal yang tidak dilakukan perintah ini adalah mengganti spasi dengan garis bawah - oh mungkin lain kali.

Derek Shaw
sumber
Ini tidak berhasil bagi saya untuk alasan apa pun, meskipun terlihat baik-baik saja. Saya mendapatkan ini berfungsi sebagai alternatif: menemukan. -exec / bin / bash -c 'mv {} `tr [AZ] [az] <<< {}`' \;
John Rix
Ini perlu prenamedari perl: dpkg -S "$(readlink -e /usr/bin/rename)"memberiperl: /usr/bin/prename
Tino
4

Banyak jawaban menggunakan program eksternal, yang sebenarnya tidak digunakan Bash.

Jika Anda tahu Anda akan memiliki Bash4 tersedia, Anda harus benar-benar hanya menggunakan ${VAR,,}notasi (mudah dan keren). Untuk Bash sebelum 4 (My Mac masih menggunakan Bash 3.2 misalnya). Saya menggunakan versi koreksi dari jawaban ghostdog74 untuk membuat versi yang lebih portabel.

Anda dapat menelepon lowercase 'my STRING'dan mendapatkan versi huruf kecil. Saya membaca komentar tentang mengatur hasilnya ke var, tetapi itu tidak benar-benar portabel Bash, karena kita tidak dapat mengembalikan string. Mencetaknya adalah solusi terbaik. Mudah ditangkap dengan sesuatu seperti var="$(lowercase $str)".

Bagaimana ini bekerja?

Cara kerjanya adalah dengan mendapatkan representasi integer ASCII dari masing-masing karakter dengan printfdan kemudian adding 32jika upper-to->lower, atau subtracting 32jika lower-to->upper. Kemudian gunakan printflagi untuk mengubah nomor kembali menjadi char. Dari 'A' -to-> 'a'kami memiliki perbedaan 32 karakter.

Menggunakan printfuntuk menjelaskan:

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

97 - 65 = 32

Dan ini adalah versi yang berfungsi dengan contoh.
Harap perhatikan komentar dalam kode, karena mereka menjelaskan banyak hal:

#!/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

Dan hasilnya setelah menjalankan ini:

$ ./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!

Ini seharusnya hanya berfungsi untuk karakter ASCII .

Bagi saya itu baik-baik saja, karena saya tahu saya hanya akan memberikan karakter ASCII.
Saya menggunakan ini untuk beberapa opsi CLI case-insensitive, misalnya.

Gus Neves
sumber
4

Kasing konversi dilakukan hanya untuk huruf. Jadi, ini harus bekerja dengan rapi.

Saya fokus pada konversi huruf antara az dari huruf besar ke huruf kecil. Setiap karakter lain hanya boleh dicetak di stdout karena ...

Mengonversi semua teks di jalur / ke / file / nama file dalam rentang az ke AZ

Untuk mengubah huruf kecil menjadi huruf besar

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

Untuk mengkonversi dari huruf besar ke huruf kecil

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

Sebagai contoh,

nama file:

my name is xyz

dikonversi menjadi:

MY NAME IS XYZ

Contoh 2:

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

Contoh 3:

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

Jika menggunakan v4, ini dibakar . Jika tidak, berikut ini adalah solusi sederhana dan dapat diterapkan secara luas . Jawaban lain (dan komentar) pada utas ini cukup membantu dalam membuat kode di bawah ini.

# 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:] )\'
}

Catatan:

  • Melakukan: a="Hi All"lalu: lcase aakan melakukan hal yang sama seperti:a=$( echolcase "Hi All" )
  • Dalam fungsi lcase, menggunakan ${!1//\'/"'\''"}alih-alih ${!1}memungkinkan ini berfungsi bahkan ketika string memiliki tanda kutip.
Stephen M. Harris
sumber
3

Untuk versi Bash lebih awal dari 4.0, versi ini harus paling cepat (karena tidak bercabang / mengeksekusi perintah apa pun):

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

jawaban technosaurus memiliki potensi juga, meskipun itu berjalan dengan baik untukku.

Orwellophile
sumber
Tidak buruk! Untuk analisis kinerja pendekatan ini, lihat jawaban saya untuk metrik.
Dejay Clayton
3

Terlepas dari berapa usia pertanyaan ini dan mirip dengan jawaban ini oleh technosaurus . Saya kesulitan menemukan solusi yang portabel di sebagian besar platform (Itu Saya Gunakan) serta versi bash yang lebih lama. Saya juga merasa frustrasi dengan array, fungsi dan penggunaan cetakan, gema dan file sementara untuk mengambil variabel sepele. Ini bekerja dengan sangat baik untuk saya sejauh ini saya pikir saya akan berbagi. Lingkungan pengujian utama saya adalah:

  1. GNU bash, versi 4.1.2 (1) -release (x86_64-redhat-linux-gnu)
  2. GNU bash, versi 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

Gaya C sederhana untuk loop untuk beralih melalui string. Untuk baris di bawah ini jika Anda belum melihat yang seperti ini sebelumnya ini adalah tempat saya belajar ini . Dalam kasus ini, baris akan memeriksa apakah char $ {input: $ i: 1} (huruf kecil) ada di input dan jika demikian menggantinya dengan char $ {ucs: $ j: 1} (huruf besar) dan menyimpannya kembali ke input.

input="${input/${input:$i:1}/${ucs:$j:1}}"
JaredTS486
sumber
Ini sangat tidak efisien, mengulang 650 kali dalam contoh Anda di atas, dan mengambil 35 detik untuk mengeksekusi 1.000 doa pada mesin saya. Untuk alternatif yang mengulang hanya 11 kali dan membutuhkan waktu kurang dari 5 detik untuk mengeksekusi 1.000 doa, lihat jawaban alternatif saya.
Dejay Clayton
1
Terima kasih, meskipun itu harus jelas hanya dengan melihatnya. Mungkin kesalahan halaman berasal dari ukuran input dan jumlah iterasi yang Anda jalankan. Meskipun demikian saya suka solusi Anda.
JaredTS486
3

Ini adalah variasi yang jauh lebih cepat dari pendekatan JaredTS486 yang menggunakan kemampuan Bash asli (termasuk versi Bash <4.0) untuk mengoptimalkan pendekatannya.

Saya telah menghitung 1.000 iterasi pendekatan ini untuk string kecil (25 karakter) dan string lebih besar (445 karakter), baik untuk konversi huruf kecil dan besar. Karena string tes sebagian besar adalah huruf kecil, konversi ke huruf kecil umumnya lebih cepat daripada huruf besar.

Saya telah membandingkan pendekatan saya dengan beberapa jawaban lain di halaman ini yang kompatibel dengan Bash 3.2. Pendekatan saya jauh lebih berkinerja daripada kebanyakan pendekatan yang didokumentasikan di sini, dan bahkan lebih cepat daripada trdalam beberapa kasus.

Berikut adalah hasil waktu untuk 1.000 iterasi 25 karakter:

  • 0,46 untuk pendekatan saya ke huruf kecil; 0,96 untuk huruf besar
  • 1,16 untuk pendekatan Orwellophile untuk huruf kecil; 1,59 untuk huruf besar
  • 3.67 untuk truntuk huruf kecil; 3.81s untuk huruf besar
  • 11.12 untuk pendekatan ghostdog74 untuk huruf kecil; 31,41 detik untuk huruf besar
  • 26.25 untuk pendekatan technosaurus untuk huruf kecil; 26.21s untuk huruf besar
  • 25.06 untuk pendekatan JaredTS486 untuk huruf kecil; 27,04 untuk huruf besar

Waktu hasil untuk 1.000 iterasi dari 445 karakter (terdiri dari puisi "The Robin" oleh Witter Bynner):

  • 2s untuk pendekatan saya ke huruf kecil; 12 untuk huruf besar
  • 4s untuk trmenjadi huruf kecil; 4s untuk huruf besar
  • 20-an untuk pendekatan Orwellophile dalam huruf kecil; 29-an untuk huruf besar
  • 75-an untuk pendekatan ghostdog74 untuk huruf kecil; 669 untuk huruf besar. Sangat menarik untuk dicatat seberapa dramatis perbedaan kinerja antara tes dengan pertandingan yang dominan vs tes dengan kesalahan yang dominan
  • 467 untuk pendekatan technosaurus untuk huruf kecil; 449 untuk huruf besar
  • 660 untuk pendekatan JaredTS486 untuk huruf kecil; 660 untuk huruf besar. Sangat menarik untuk dicatat bahwa pendekatan ini menghasilkan kesalahan halaman terus menerus (pertukaran memori) di Bash

Larutan:

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

Pendekatannya sederhana: sementara string input memiliki huruf besar yang tersisa, temukan yang berikutnya, dan ganti semua instance dari huruf itu dengan varian huruf kecilnya. Ulangi sampai semua huruf besar diganti.

Beberapa karakteristik kinerja solusi saya:

  1. Hanya menggunakan utilitas builtin shell, yang menghindari overhead dari memanggil utilitas biner eksternal dalam proses baru
  2. Hindari sub-shell, yang dikenai penalti kinerja
  3. Menggunakan mekanisme shell yang dikompilasi dan dioptimalkan untuk kinerja, seperti penggantian string global dalam variabel, pemangkasan akhiran variabel, dan pencarian dan pencocokan regex. Mekanisme-mekanisme ini jauh lebih cepat daripada iterasi secara manual melalui string
  4. Ulangi hanya beberapa kali yang diperlukan oleh hitungan karakter pencocokan unik untuk dikonversi. Misalnya, mengonversi string yang memiliki tiga karakter huruf besar berbeda menjadi huruf kecil hanya memerlukan 3 iterasi loop. Untuk alfabet ASCII yang telah dikonfigurasikan, jumlah iterasi loop maksimum adalah 26
  5. UCSdan LCSdapat ditambah dengan karakter tambahan
Dejay Clayton
sumber
2

Untuk menyimpan string yang diubah menjadi variabel. Mengikuti berhasil bagi saya - $SOURCE_NAMEuntuk$TARGET_NAME

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

Cara sederhana

echo "Hi all" | awk '{ print tolower($0); }'
Atul23
sumber