Bir dizeyi Bash'te küçük harfe nasıl dönüştürebilirim?


Yanıtlar:


2180

Çeşitli yollar vardır:

POSIX standardı

tr

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

AWK

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

Sigara POSIX

Aşağıdaki örneklerle taşınabilirlik sorunlarıyla karşılaşabilirsiniz:

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

darbe

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

Not: Bu konuda YMMV. Benim için çalışmıyor (GNU bash sürüm 4.2.46 ve 4.0.33 (ve aynı davranış 2.05b.0 ancak nocasematch uygulanmadı)) shopt -u nocasematch;. Nocasematch'in [["fooBaR" == "FOObar"]] öğesinin, [bz] tuhaf bir şekilde [AZ] ile yanlış eşleştirilmesi durumunda Tamam AMA ile eşleşmesine neden olduğunda. Bash, çift negatif ("ayarsız nocasematch") ile karıştırılır! :-)


9
Bir şey mi kaçırıyorum, yoksa son örneğiniz (Bash'te) aslında tamamen farklı bir şey yapıyor mu? Bu "ABX" için çalışır, ancak bunun yerine yaparsanız word="Hi All"diğer örneklerde olduğu gibi, bu döner hadeğil hi all. Yalnızca büyük harfler için çalışır ve zaten küçük harfleri atlar.
jangosteve

26
POSIX standardında yalnızca trve awkörneklerinin belirtildiğini unutmayın .
Richard Hansen

178
tr '[:upper:]' '[:lower:]'büyük / küçük harf eşdeğerlerini belirlemek için geçerli yerel ayarı kullanır, böylece aksan işaretli harfler kullanan yerel ayarlarla çalışır.
Richard Hansen

10
Çıktı nasıl yeni bir değişkene dönüşür? Yani küçük harfli dizenin yeni bir değişkene girmesini istiyorum?
Adam Parkin

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

435

Bash 4'te:

Küçük harf yapmak

$ 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

Büyük harfe

$ 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

Geçiş yap (belgelenmemiş, ancak derleme zamanında isteğe bağlı olarak yapılandırılabilir)

$ 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

Büyük harf kullanımı (belgesiz, ancak isteğe bağlı olarak derleme zamanında yapılandırılabilir)

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

Başlık durumu:

$ 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

Bir declareözelliği kapatmak için tuşunu kullanın +. Örneğin declare +c string,. Bu, geçerli değeri değil, sonraki atamaları etkiler.

declareSeçenekler değişkenin niteliğini değil, içeriği değişir. Örneklerimdeki yeniden atamalar, değişiklikleri göstermek için içeriği günceller.

Düzenle:

Ghostdog74${var~} tarafından önerildiği gibi "kelimeye göre ilk karakteri değiştir" ( ) eklendi .

Düzenleme: Bash 4.3 eşleşmesi için düzeltilmiş tilde davranışı düzeltildi.


5
Oldukça bizzare, "^^" ve ",," operatörler ASCII olmayan karakterler üzerinde çalışmaz ama "~~ " işe yarar ... Yani "ŁÓDŹ" string="łódź"; echo ${string~~}, ancak echo ${string^^}"łóDź" döndürür. Hatta LC_ALL=pl_PL.utf-8. Bash 4.2.24 kullanıyor.
Hubert Kario

2
@ HubertKario: Bu garip. Aynı dize ile Bash 4.0.33 benim için aynı en_US.UTF-8. Bu bir hata ve bunu rapor ettim.
sonraki duyuruya kadar duraklatıldı.

1
@ HubertKario: Deneyin echo "$string" | tr '[:lower:]' '[:upper:]'. Muhtemelen aynı başarısızlığı sergileyecektir. Yani sorun en azından kısmen Bash'ın değil.
sonraki duyuruya kadar duraklatıldı.

1
@DennisWilliamson: Evet, ben de fark ettim (Shuvalov cevabının yorumuna bakınız). Ben sadece, "bu şeyler sadece ASCII içindir", ama sonra işe yarayan "~~" operatörü, bu yüzden kod ve çeviri tabloları zaten orada değil gibi değil ...
Hubert Kario

4
@HubertKario: Bash görevlisi hatayı kabul etti ve bir sonraki sürümde düzeltileceğini belirtti.
sonraki duyuruya kadar duraklatıldı.

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

4
@RichardHansen: ACII trdışı karakterler için benim için çalışmıyor. Doğru yerel ayar kümesi ve yerel dosyaları oluşturulan var. Neyi yanlış yapabileceğime dair bir fikrin var mı?
Hubert Kario

Bilginize: Bu Windows / Msys üzerinde çalıştı. Diğer bazı önerilerde bulunmadı.
wasatchwizard

3
Neden [:upper:]ihtiyaç duyulur?
mgutt

77

tr :

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

AWK :

{ print tolower($0) }

sed :

y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/

2
+1 a="$(tr [A-Z] [a-z] <<< "$a")"benim için en kolay görünüyor. Hala
acemiyim

2
sedÇözümü şiddetle tavsiye ederim ; Bir sebepten ötürü olmayan bir ortamda çalışıyordum trama henüz bir sistem bulamadım sed, artı bunu yapmak istediğim çoğu zaman sedzaten başka bir şey yaptım zaten komutları birlikte tek (uzun) bir ifadeye dönüştürür.
Haravikk

2
Köşeli ayraç ifadeleri tırnak içine alınmalıdır. İçinde tr [A-Z] [a-z] A, tek bir harf veya nullgob içeren dosya adları varsa kabuk dosya adı genişletmesi gerçekleştirebilir . tr "[A-Z]" "[a-z]" Adüzgün davranacaktır.
Dennis

2
@CamiloMartin bu sorunu yaşadığım bir BusyBox sistemidir, özellikle Synology NASes, ancak birkaç başka sistemde de karşılaştım. Son zamanlarda bir çok çapraz platform kabuk komut dosyası yapıyorum ve ekstra bir şey yüklenmemesi şartıyla işleri çok zorlaştırıyor! Ancak henüz bir sistemle karşılaşmadımsed
Haravikk

2
Bunun tr [A-Z] [a-z]neredeyse tüm yerel ayarlarda yanlış olduğunu unutmayın . örneğin, en-USyerel ayar, A-Zaslında aralıktır AaBbCcDdEeFfGgHh...XxYyZ.
fuz

44

Bu eski bir yazı olduğunu biliyorum ama bu cevabı başka bir site için yaptım, bu yüzden buraya göndereceğimi düşündüm:

ÜST -> alt : python kullan:

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

Veya Ruby:

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

Veya Perl (muhtemelen benim favorim):

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

Veya PHP:

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

Veya Awk:

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

Veya Sed:

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

Veya Bash 4:

b=${a,,}

Veya NodeJS'iniz varsa (ve biraz deli iseniz ...):

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

Ayrıca kullanabilirsiniz dd(ama olmaz!):

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

alt -> ÜST :

python kullan:

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

Veya Ruby:

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

Veya Perl (muhtemelen benim favorim):

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

Veya PHP:

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

Veya Awk:

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

Veya Sed:

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

Veya Bash 4:

b=${a^^}

Veya NodeJS'iniz varsa (ve biraz deli iseniz ...):

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

Ayrıca kullanabilirsiniz dd(ama olmaz!):

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

Ayrıca 'kabuk' derken ne demek tahmin ediyorum bashama kullanabilirsiniz eğer zshkolay olduğu kadar var

b=$a:l

küçük harf ve

b=$a:u

büyük harf için.


@JESii benim için üst -> alt ve alt -> üst için çalışır. 64bit Debian Stretch'te sed 4.2.2 ve Bash 4.3.42 (1) kullanıyorum.
nettux

1
Merhaba, @ nettux443 ... Ben sadece bash operasyonunu tekrar denedim ve hala "kötü ikame" hata mesajıyla başarısız oluyor. Homebrew'ın bash'ını kullanarak OSX kullanıyorum: GNU bash, sürüm 4.3.42 (1) -release (x86_64-apple-darwin14.5.0)
JESii

5
Kullanmayın! Bir senaryo oluşturan tüm örnekler son derece kırılgandır; değeri atek bir teklif içeriyorsa, yalnızca davranışı değil ciddi bir güvenlik sorununu da çözdünüz demektir.
Üçlü

Sed çözümünü en çok seviyorum, çünkü sed her zaman her yerde bulunur.
Dudi Boy

DD çözümünü kullanmayı tercih ederim.
Çalıştırmak


18

GNU kullanma sed:

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

Misal:

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

12

Ön Bash 4.0

Bash Bir dizgenin Büyük / Küçük Harf Durumunu Azalt ve değişken

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

echo "$VARIABLE"

5
echoVe borulara gerek yok : kullanım$(tr '[:upper:]' '[:lower:]' <<<"$VARIABLE")
Tino

3
@Tino Buradaki dize, Bash'ın gerçekten eski sürümlerine de taşınabilir değil; V3'te tanıtıldığına inanıyorum.
Üçlü

1
@tripleee Haklısınız, bash-2.05b'de tanıtıldı - ancak bu benim sistemlerimde bulabildiğim en eski bash
Tino

11

Yalnızca yerleşikleri kullanan standart bir kabuk için (bashisms olmadan):

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

Ve büyük harf için:

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

FreeBSD'de taşınabilir olmadığı için bu komut dosyasında bazı bashizme izin vermediyseniz merak ediyorum: $ {1: $ ...}: Kötü ikame
Dereckson

2
Aslında; alt dizeleri ${var:1:1}bir Bashizmdir.
tripleee

Bu yaklaşım oldukça kötü performans metriklerine sahiptir. Metrikler için cevabıma bakın.
Dejay Clayton

9

Bash 4'te dizgi kullanabilirsiniz

Misal:

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


7

Düzenli ifade

Paylaşmak istediğim komut için kredi almak istiyorum ama gerçek şu ki, kendi kullanımım için http://commandlinefu.com adresinden edindim . Bu avantaja sahiptir eğer cdo yinelemeli harfe dikkatli kullanımını memnun etmek tüm dosya ve klasörleri değişecek olan kendi ev klasörü içinde herhangi bir dizine. Mükemmel bir komut satırı düzeltmesi ve özellikle sürücünüzde sakladığınız çok sayıda albüm için kullanışlıdır.

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

Bulunduktan sonra, geçerli dizini veya tam yolu belirten nokta (.) Yerine bir dizin belirtebilirsiniz.

Umarım bu çözüm, bu komutun yapmadığı bir şeyi boşlukları alt çizgilerle değiştirmektir - ah başka bir zaman.


Her ne sebeple olursa olsun bu benim için işe yaramadı, ancak iyi görünüyor. Bunu alternatif olarak çalışmak için aldım: find. -exec / bin / bash -c 'mv {} `tr [AZ] [az] <<< {}`' \;
John Rix

Bu ihtiyacı prenamedan perl: dpkg -S "$(readlink -e /usr/bin/rename)"verirperl: /usr/bin/prename
Tino

4

Gerçekten kullanmayan harici programları kullanarak birçok cevap Bash.

Bash4'ü kullanabileceğinizi biliyorsanız gerçekten ${VAR,,}notasyonu kullanmalısınız (kolay ve havalı). 4'ten önceki Bash için (Mac'im hala Bash 3.2 kullanıyor). Daha taşınabilir bir sürüm oluşturmak için @ ghostdog74 yanıtının düzeltilmiş sürümünü kullandım.

Birini arayabilir lowercase 'my STRING've küçük harfli bir sürüm alabilirsiniz. Sonucu bir var değerine ayarlama hakkındaki yorumları okudum, ancak Bashdizeleri döndüremeyeceğimiz için bu gerçekten taşınabilir değil. Yazdırmak en iyi çözümdür. Gibi bir şey ile yakalamak kolay var="$(lowercase $str)".

Bu nasıl çalışır?

Bunun çalışma şekli, her bir karakterin ASCII tamsayı temsilini printfve sonra adding 32if upper-to->lowerveya subtracting 32if ile elde etmektir lower-to->upper. Sonra printfnumarayı tekrar karaktere dönüştürmek için tekrar kullanın. Gönderen 'A' -to-> 'a'biz 32 karakterlerin bir fark var.

Açıklamak için kullanma printf:

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

97 - 65 = 32

Ve bu örneklerle çalışan versiyon.
Bir çok şeyi açıkladıkları için lütfen koddaki yorumları not edin:

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

Ve bunu çalıştırdıktan sonra sonuçlar:

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

Bu sadece ASCII karakterleri için çalışmalıdır .

Benim için sorun değil, çünkü sadece ASCII karakterlerini aktaracağımı biliyorum.
Örneğin, büyük / küçük harfe duyarlı olmayan CLI seçenekleri için kullanıyorum.


4

Dönüştürme durumu yalnızca alfabe için yapılır. Yani, bu düzgün çalışmalı.

Az harfli harfleri büyük harften küçük harfe dönüştürmeye odaklanıyorum. Diğer karakterler sadece olduğu gibi stdout'ta yazdırılmalıdır ...

Az aralıktaki yol / dosya / dosya adı içindeki tüm metni AZ'ye dönüştürür

Küçük harfleri büyük harfe dönüştürmek için

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

Büyük harften küçük harfe dönüştürmek için

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

Örneğin,

dosya adı:

my name is xyz

dönüştürülür:

MY NAME IS XYZ

Örnek 2:

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

Örnek 3:

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

3

V4 kullanıyorsanız, bu pişmiş . Değilse, burada basit ve yaygın olarak uygulanabilir bir çözüm var. Bu ileti dizisindeki diğer yanıtlar (ve yorumlar) aşağıdaki kodu oluştururken oldukça yardımcı oldu.

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

Notlar:

  • Yapmak: a="Hi All"ve sonra: lcase aaynı şeyi yapacaktır:a=$( echolcase "Hi All" )
  • Lcase işlevinde, ${!1//\'/"'\''"}bunun yerine kullanmak ${!1}, dizede tırnak işareti olsa bile çalışmasına izin verir.

3

4.0'dan önceki Bash sürümleri için, bu sürüm en hızlı olmalıdır ( herhangi bir komutu çatallama / çalıştırmadığından ):

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

technosaurus'un cevabı da benim için doğru bir şekilde çalışmasına rağmen potansiyeli vardı.


Fena değil! Bu yaklaşımın performansının analizi için lütfen metrikler için cevabım bölümüne bakın.
Dejay Clayton

3

Bu sorunun kaç yaşında olmasına rağmen ve technosaurus'un bu cevabına benzer . Çoğu platformda (That I Use) yanı sıra bash'ın eski sürümlerinde taşınabilir bir çözüm bulmakta zorlandım. Ayrıca önemsiz değişkenleri almak için diziler, işlevler ve baskılar, ekolar ve geçici dosyaların kullanımı ile de hayal kırıklığına uğradım. Bu benim için şimdiye kadar çok iyi çalışıyor, paylaşacağımı düşündüm. Ana test ortamlarım:

  1. GNU bash, sürüm 4.1.2 (1) -çalışma (x86_64-redhat-linux-gnu)
  2. GNU bash, sürüm 3.2.57 (1) -çalışma (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

Dizeleri yinelemek için döngü için basit C stili . Aşağıdaki satır için daha önce böyle bir şey görmediyseniz , bunu öğrendim . Bu durumda satır, girişte $ {input: $ i: 1} (küçük harf) karakterinin var olup olmadığını kontrol eder ve eğer öyleyse verilen char $ {ucs: $ j: 1} (büyük harf) ile değiştirir ve saklar geri girdi.

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

Bu, çılgınca verimsizdir, yukarıdaki örnekte 650 kez döngü yapar ve makinemde 1000 çağrıyı yürütmek için 35 saniye sürer. 1000 çağrıyı gerçekleştirmek için sadece 11 kez döngü yapan ve 5 saniyeden daha kısa süren bir alternatif için alternatif cevabımı inceleyin.
Dejay Clayton

1
Teşekkürler, ancak bu sadece ona bakarak açık olmalıdır. Belki de sayfa hataları giriş boyutundan ve yürüttüğünüz yineleme sayısından kaynaklanır. Yine de çözümünüzü seviyorum.
JaredTS486

3

Bu, yaklaşımını optimize etmek için yerel Bash yeteneklerini (Bash sürümleri <4.0 dahil) kullanan JaredTS486'nın yaklaşımının çok daha hızlı bir varyasyonudur .

Küçük ve dize dönüşümleri için küçük bir dize (25 karakter) ve daha büyük bir dize (445 karakter) için bu yaklaşımın 1.000 yinelemesini zamanladım. Test dizeleri ağırlıklı olarak küçük harf olduğundan, küçük harfe dönüştürmeler genellikle büyük harfe göre daha hızlıdır.

Yaklaşımımı, bu sayfada Bash 3.2 ile uyumlu diğer birkaç cevapla karşılaştırdım. Benim yaklaşımım burada belgelenen çoğu yaklaşımdan çok daha başarılıdır trve bazı durumlarda olduğundan daha hızlıdır .

İşte 25 karakterlik 1.000 yineleme için zamanlama sonuçları:

  • Küçük harfe yaklaşımım için 0,46s; Büyük harf için 0.96s
  • Orwellophile'ın küçük harfe yaklaşımı için 1.16s ; 1.59s büyük harf için
  • trKüçük harf için 3.67s ; Büyük harf için 3.81s
  • Ghostdog74'ün küçük harfe yaklaşımı için 11.12'ler ; Büyük harf için 31.41s
  • Technosaurus'un küçük harfe yaklaşımı için 26,25 ; Büyük harf için 26.21s
  • JaredTS486'nın küçük harfe yaklaşımı için 25.06'lar ; Büyük harf için 27.04s

445 karakterlik 1.000 tekrarlama için zamanlama sonuçları (Witter Bynner'ın "The Robin" şiirinden oluşur):

  • Küçük harflere yaklaşımım için 2s; Büyük harf için 12'ler
  • trKüçük harf için 4 s ; Büyük harf için 4s
  • Orwellophile'ın küçük harfe yaklaşımı için 20'ler ; Büyük harf için 29s
  • Ghostdog74'ün küçük harfe yaklaşımı için 75'ler ; Büyük harf için 669s. Baskın eşleşmelere sahip bir test ile baskın özlüyor içeren bir test arasında performans farkının ne kadar dramatik olduğunu not etmek ilginçtir.
  • Technosaurus'un küçük harfe yaklaşımı için 467'ler ; Büyük harf için 449s
  • JaredTS486'nın küçük harfe yaklaşımı için 660'lar ; Büyük harf için 660'lar. Bu yaklaşımın Bash'te sürekli sayfa hataları (bellek değişimi) oluşturduğunu belirtmek ilginçtir.

Çözüm:

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

Yaklaşım basittir: giriş dizesinde kalan büyük harfler varsa, bir sonrakini bulun ve bu harfin tüm örneklerini küçük harfli değişkenle değiştirin. Tüm büyük harfler değiştirilene kadar tekrarlayın.

Çözümümün bazı performans özellikleri:

  1. Yalnızca kabuk yerleşik yardımcı programları kullanır, bu da yeni bir işlemde harici ikili yardımcı programları çağırmanın yükünü ortadan kaldırır
  2. Performans cezalarına neden olan alt mermilerden kaçınır
  3. Değişkenler içindeki global dize değiştirme, değişken sonek kırpma ve normal ifade arama ve eşleştirme gibi performans için derlenen ve optimize edilen kabuk mekanizmalarını kullanır. Bu mekanizmalar, dizeler aracılığıyla manuel olarak yinelemekten çok daha hızlıdır
  4. Yalnızca dönüştürülecek benzersiz eşleşen karakter sayısı için gereken sayıda döngüyü döndürür. Örneğin, üç farklı büyük harfli bir dizeyi küçük harfe dönüştürmek için yalnızca 3 döngü yinelemesi gerekir. Önceden yapılandırılmış ASCII alfabesi için maksimum döngü yineleme sayısı 26'dır.
  5. UCSve LCSek karakterlerle zenginleştirilebilir

2

Dönüştürülen dizeyi bir değişkene depolamak için. Aşağıdaki benim için çalıştı - $SOURCE_NAMEiçin$TARGET_NAME

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

1

Basit yol

echo "Hi all" | awk '{ print tolower($0); }'
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.