Wie konvertiere ich eine Zeichenfolge in Bash in Kleinbuchstaben?


Antworten:


2180

Es gibt verschiedene Möglichkeiten:

POSIX-Standard

tr

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

AWK

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

Nicht-POSIX

Bei den folgenden Beispielen können Portabilitätsprobleme auftreten:

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

Hinweis: YMMV in diesem Fall. Funktioniert bei mir nicht (GNU Bash Version 4.2.46 und 4.0.33 (und gleiches Verhalten 2.05b.0, aber Nocasematch ist nicht implementiert)), selbst bei Verwendung shopt -u nocasematch;. Das Deaktivieren dieser Nichtübereinstimmung führt dazu, dass [["fooBaR" == "FOObar"]] mit OK übereinstimmt, ABER im Fall, dass [bz] seltsamerweise mit [AZ] falsch übereinstimmt. Bash wird durch das Doppel-Negativ verwirrt ("Nocasematch nicht setzen")! :-)


9
Vermisse ich etwas oder macht Ihr letztes Beispiel (in Bash) tatsächlich etwas völlig anderes? Es funktioniert für "ABX", aber wenn Sie stattdessen word="Hi All"wie die anderen Beispiele machen, wird es hanicht zurückgegeben hi all. Es funktioniert nur für Großbuchstaben und überspringt die bereits in Kleinbuchstaben geschriebenen Buchstaben.
Jangosteve

26
Beachten Sie, dass im POSIX-Standard nur die Beispiele trund awkangegeben sind.
Richard Hansen

178
tr '[:upper:]' '[:lower:]'verwendet das aktuelle Gebietsschema, um Groß- / Kleinbuchstaben zu ermitteln, sodass es mit Gebietsschemas funktioniert, die Buchstaben mit diakritischen Zeichen verwenden.
Richard Hansen

10
Wie bekommt man die Ausgabe in eine neue Variable? Das heißt, ich möchte die Zeichenfolge in Kleinbuchstaben in eine neue Variable umwandeln?
Adam Parkin

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

435

In Bash 4:

In Kleinbuchstaben

$ 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

In Großbuchstaben

$ 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

Umschalten (undokumentiert, aber zur Kompilierungszeit optional konfigurierbar)

$ 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

Großschreibung (undokumentiert, aber zur Kompilierungszeit optional konfigurierbar)

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

Titelfall:

$ 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

declareVerwenden Sie zum Deaktivieren eines Attributs +. Zum Beispiel declare +c string. Dies wirkt sich auf nachfolgende Zuordnungen und nicht auf den aktuellen Wert aus.

Die declareOptionen ändern das Attribut der Variablen, nicht jedoch den Inhalt. Die Neuzuweisungen in meinen Beispielen aktualisieren den Inhalt, um die Änderungen anzuzeigen.

Bearbeiten:

Es wurde "erstes Zeichen nach Wort umschalten " ( ${var~}) hinzugefügt, wie von ghostdog74 vorgeschlagen .

Bearbeiten: Das Tilde-Verhalten wurde korrigiert, um mit Bash 4.3 übereinzustimmen.


5
Ziemlich bizzare, "^^" - und ",," -Operatoren funktionieren nicht mit Nicht-ASCII-Zeichen, aber "~~" funktioniert ... string="łódź"; echo ${string~~}Gibt also "ŁÓDŹ" zurück, gibt aber echo ${string^^}"łóDź" zurück. Auch in LC_ALL=pl_PL.utf-8. Das ist Bash 4.2.24.
Hubert Kario

2
@ HubertKario: Das ist komisch. Es ist dasselbe für mich in Bash 4.0.33 mit der gleichen Zeichenfolge in en_US.UTF-8. Es ist ein Fehler und ich habe ihn gemeldet.
Bis auf weiteres angehalten.

1
@ HubertKario: Versuchen Sie es echo "$string" | tr '[:lower:]' '[:upper:]'. Es wird wahrscheinlich den gleichen Fehler aufweisen. Das Problem ist also zumindest teilweise nicht das von Bash.
Bis auf weiteres angehalten.

1
@ TennisWilliamson: Ja, das habe ich auch bemerkt (siehe Kommentar zur Antwort von Shuvalov). Ich würde nur sagen, "dieses Zeug ist nur für ASCII", aber dann funktioniert der Operator "~~", also ist es nicht so, dass der Code und die Übersetzungstabellen nicht bereits vorhanden sind ...
Hubert Kario

4
@HubertKario: Die Bash Maintainer hat bestätigt den Fehler und erklärte , dass es in der nächsten Version behoben werden.
Bis auf weiteres angehalten.

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

4
@ RichardHansen: trfunktioniert bei mir nicht für Nicht-ACII-Zeichen. Ich habe korrekte Gebietsschemasätze und Gebietsschemadateien generiert. Haben Sie eine Idee, was ich falsch machen könnte?
Hubert Kario

Zu Ihrer Information: Dies funktionierte unter Windows / Msys. Einige der anderen Vorschläge haben dies nicht getan.
Wasatchwizard

3
Warum wird [:upper:]benötigt?
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")"sieht für mich am einfachsten aus. Ich bin noch ein Anfänger ...
Sandeepan Nath

2
Ich empfehle die sedLösung nachdrücklich . Ich habe in einer Umgebung gearbeitet, die es aus irgendeinem Grund nicht gibt, traber ich habe noch kein System ohne gefunden sed. Außerdem habe ich die meiste Zeit, in der ich dies tun möchte, sedsowieso etwas anderes getan, damit ich es verketten kann die Befehle zusammen zu einer einzigen (langen) Anweisung.
Haravikk

2
Die Klammerausdrücke sollten in Anführungszeichen gesetzt werden. In tr [A-Z] [a-z] Akann die Shell eine Dateinamenerweiterung durchführen, wenn Dateinamen aus einem einzelnen Buchstaben bestehen oder ein Nullgob festgelegt ist. tr "[A-Z]" "[a-z]" Awird sich richtig verhalten.
Dennis

2
@CamiloMartin Es ist ein BusyBox-System, bei dem ich dieses Problem habe, insbesondere bei Synology NASes, aber ich habe es auch auf einigen anderen Systemen festgestellt. Ich habe in letzter Zeit viel plattformübergreifendes Shell-Scripting durchgeführt, und mit der Anforderung, dass nichts extra installiert werden muss, macht es die Dinge sehr schwierig! Allerdings habe ich noch kein System ohnesed
Haravikk

2
Beachten Sie, dass dies tr [A-Z] [a-z]in fast allen Ländereinstellungen falsch ist. Im en-USGebietsschema A-Zist beispielsweise das Intervall angegeben AaBbCcDdEeFfGgHh...XxYyZ.
Fuz

44

Ich weiß, dass dies ein alter Beitrag ist, aber ich habe diese Antwort für eine andere Website gegeben, also dachte ich, ich würde sie hier veröffentlichen:

UPPER -> lower : Verwenden Sie Python:

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

Oder Ruby:

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

Oder Perl (wahrscheinlich mein Favorit):

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

Oder PHP:

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

Oder Awk:

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

Oder Sed:

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

Oder Bash 4:

b=${a,,}

Oder NodeJS, wenn Sie es haben (und ein bisschen verrückt sind ...):

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

Sie könnten auch verwenden dd(aber ich würde nicht!):

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

niedriger -> OBER :

Verwenden Sie Python:

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

Oder Ruby:

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

Oder Perl (wahrscheinlich mein Favorit):

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

Oder PHP:

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

Oder Awk:

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

Oder Sed:

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

Oder Bash 4:

b=${a^^}

Oder NodeJS, wenn Sie es haben (und ein bisschen verrückt sind ...):

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

Sie könnten auch verwenden dd(aber ich würde nicht!):

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

Auch wenn Sie "Shell" sagen, nehme ich an, Sie meinen, bashaber wenn Sie es verwenden können, ist zshes so einfach wie

b=$a:l

für Kleinbuchstaben und

b=$a:u

für Großbuchstaben.


@JESii beide arbeiten für mich oben -> unten und unten-> oben. Ich verwende sed 4.2.2 und Bash 4.3.42 (1) auf 64-Bit-Debian-Stretch.
Nettux

1
Hallo, @ nettux443 ... Ich habe gerade die Bash-Operation erneut versucht und sie schlägt für mich immer noch mit der Fehlermeldung "Bad Substitution" fehl. Ich bin unter OSX mit Homebrews Bash: GNU Bash, Version 4.3.42 (1) -Veröffentlichung (x86_64-apple-darwin14.5.0)
JESii

5
Verwende nicht! Alle Beispiele, die ein Skript generieren, sind extrem spröde. Wenn der Wert von aein einfaches Anführungszeichen enthält, haben Sie nicht nur ein fehlerhaftes Verhalten, sondern auch ein ernstes Sicherheitsproblem.
Tripleee

Ich mag die sed-Lösung am meisten, da sed immer allgegenwärtig ist.
Dudi Boy

Ich bevorzuge die Verwendung der dd-Lösung. Bitte beachten Sie, dass Sie root sein müssen, damit es funktioniert
inetphantom


18

Verwenden von GNU sed:

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

Beispiel:

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

12

Pre Bash 4.0

Bash Senken Sie die Groß- / Kleinschreibung einer Zeichenfolge und weisen Sie sie einer Variablen zu

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

echo "$VARIABLE"

5
Keine Notwendigkeit für echound Rohre: Verwendung$(tr '[:upper:]' '[:lower:]' <<<"$VARIABLE")
Tino

3
@Tino Der Here-String ist auch nicht auf wirklich alte Versionen von Bash portierbar. Ich glaube, es wurde in v3 eingeführt.
Tripleee

1
@tripleee Sie haben Recht, es wurde in Bash-2.05b eingeführt - aber das ist die älteste Bash, die ich auf meinen Systemen finden konnte
Tino

11

Für eine Standard-Shell (ohne Bashismen), die nur eingebaute verwendet:

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

Und für Großbuchstaben:

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

Ich frage mich, ob Sie in diesem Skript keinen Bashismus zugelassen haben, da es auf FreeBSD nicht portierbar ist. Sh: $ {1: $ ...}: Schlechte Substitution
Dereckson

2
Tatsächlich; Teilzeichenfolgen mit ${var:1:1}sind ein Baschismus.
Tripleee

Dieser Ansatz weist ziemlich schlechte Leistungsmetriken auf. Siehe meine Antwort für Metriken.
Dejay Clayton

9

In Bash 4 können Sie den Satz verwenden

Beispiel:

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


7

Regulären Ausdruck

Ich möchte den Befehl, den ich teilen möchte, gutschreiben, aber die Wahrheit ist, dass ich ihn für meinen eigenen Gebrauch von http://commandlinefu.com erhalten habe . Es hat den Vorteil, dass wenn Sie cdin ein Verzeichnis in Ihrem eigenen Home-Ordner wechseln, alle Dateien und Ordner rekursiv in Kleinbuchstaben geändert werden, verwenden Sie diese bitte mit Vorsicht. Es ist eine brillante Befehlszeilenkorrektur und besonders nützlich für die Vielzahl von Alben, die Sie auf Ihrem Laufwerk gespeichert haben.

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

Sie können anstelle des Punkts (.) Nach der Suche ein Verzeichnis angeben, das das aktuelle Verzeichnis oder den vollständigen Pfad angibt.

Ich hoffe, diese Lösung erweist sich als nützlich. Das einzige, was dieser Befehl nicht tut, ist, Leerzeichen durch Unterstriche zu ersetzen - na ja, vielleicht ein anderes Mal.


Das hat bei mir aus irgendeinem Grund nicht funktioniert, obwohl es gut aussieht. Ich habe dies jedoch als Alternative zum Laufen gebracht: Finden. -exec / bin / bash -c 'mv {} `tr [AZ] [az] <<< {}`' \;
John Rix

Dies muss prenamevon perl: dpkg -S "$(readlink -e /usr/bin/rename)"gibtperl: /usr/bin/prename
Tino

4

Viele Antworten mit externen Programmen, die nicht wirklich verwendet werden Bash.

Wenn Sie wissen, dass Sie Bash4 zur Verfügung haben, sollten Sie wirklich nur die ${VAR,,}Notation verwenden (es ist einfach und cool). Für Bash vor 4 (Mein Mac verwendet zum Beispiel immer noch Bash 3.2). Ich habe die korrigierte Version der Antwort von @ ghostdog74 verwendet, um eine portablere Version zu erstellen.

Eine, die Sie anrufen lowercase 'my STRING'und eine Kleinbuchstabenversion erhalten können. Ich habe Kommentare zum Setzen des Ergebnisses auf eine Variable gelesen, aber das ist nicht wirklich portabel Bash, da wir keine Zeichenfolgen zurückgeben können. Drucken ist die beste Lösung. Einfach mit so etwas zu erfassen var="$(lowercase $str)".

Wie das funktioniert

Dies funktioniert, indem die ASCII-Ganzzahldarstellung jedes Zeichens mit printfund dann adding 32if upper-to->loweroder subtracting 32if abgerufen wird lower-to->upper. Verwenden Sie dann printferneut, um die Zahl wieder in ein Zeichen umzuwandeln. Von haben 'A' -to-> 'a'wir einen Unterschied von 32 Zeichen.

Verwenden printf, um zu erklären:

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

97 - 65 = 32

Und dies ist die Arbeitsversion mit Beispielen.
Bitte beachten Sie die Kommentare im Code, da sie viele Dinge erklären:

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

Und die Ergebnisse nach dem Ausführen:

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

Dies sollte jedoch nur für ASCII-Zeichen funktionieren .

Für mich ist es in Ordnung, da ich weiß, dass ich nur ASCII-Zeichen weitergeben werde.
Ich verwende dies zum Beispiel für einige CLI-Optionen, bei denen die Groß- und Kleinschreibung nicht berücksichtigt wird.


4

Das Konvertieren von Groß- und Kleinschreibung erfolgt nur für Alphabete. Das sollte also ordentlich funktionieren.

Ich konzentriere mich auf die Konvertierung von Alphabeten zwischen az von Groß- in Kleinbuchstaben. Alle anderen Zeichen sollten so wie sie sind in stdout gedruckt werden ...

Konvertiert den gesamten Text im Pfad / in / Datei / Dateiname im Az-Bereich in AZ

Zum Konvertieren von Kleinbuchstaben in Großbuchstaben

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

Zum Konvertieren von Groß- in Kleinbuchstaben

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

Zum Beispiel,

Dateiname:

my name is xyz

wird konvertiert zu:

MY NAME IS XYZ

Beispiel 2:

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

Beispiel 3:

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

3

Wenn Sie v4 verwenden, ist dies eingebrannt . Wenn nicht, finden Sie hier eine einfache, allgemein anwendbare Lösung. Andere Antworten (und Kommentare) zu diesem Thread waren beim Erstellen des folgenden Codes sehr hilfreich.

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

Anmerkungen:

  • Tun: a="Hi All"und dann: lcase awird das Gleiche tun wie:a=$( echolcase "Hi All" )
  • In der Funktion lcase ermöglicht die Verwendung von ${!1//\'/"'\''"}anstelle von, ${!1}dass dies auch dann funktioniert, wenn die Zeichenfolge Anführungszeichen enthält.

3

Für Bash-Versionen vor 4.0 sollte diese Version am schnellsten sein (da keine Befehle gegabelt / ausgeführt werden):

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

Die Antwort von technosaurus hatte auch Potenzial, obwohl sie für mich richtig lief.


Nicht schlecht! Eine Analyse der Leistung dieses Ansatzes finden Sie in meiner Antwort für Metriken.
Dejay Clayton

3

Trotz des Alters dieser Frage und ähnlich dieser Antwort von Technosaurus . Es fiel mir schwer, eine Lösung zu finden, die auf den meisten Plattformen (die ich verwende) sowie auf älteren Versionen von Bash portabel war. Ich war auch frustriert über Arrays, Funktionen und die Verwendung von Ausdrucken, Echos und temporären Dateien zum Abrufen trivialer Variablen. Das funktioniert sehr gut für mich, bis jetzt dachte ich, ich würde teilen. Meine Haupttestumgebungen sind:

  1. GNU Bash, Version 4.1.2 (1) -Veröffentlichung (x86_64-redhat-linux-gnu)
  2. GNU Bash, Version 3.2.57 (1) -Veröffentlichung (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

Einfache C-artige for-Schleife zum Durchlaufen der Zeichenfolgen. Für die folgende Zeile, wenn Sie so etwas noch nicht gesehen haben, habe ich dies hier gelernt . In diesem Fall prüft die Zeile, ob das Zeichen $ {input: $ i: 1} (Kleinbuchstaben) in der Eingabe vorhanden ist, und ersetzt es in diesem Fall durch das angegebene Zeichen $ {ucs: $ j: 1} (Großbuchstaben) und speichert es zurück in die Eingabe.

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

Dies ist äußerst ineffizient, da in Ihrem obigen Beispiel eine 650-fache Schleife durchgeführt wird und 35 Sekunden benötigt werden, um 1000 Aufrufe auf meinem Computer auszuführen. Eine Alternative, die nur elf Mal wiederholt wird und weniger als 5 Sekunden benötigt, um 1000 Aufrufe auszuführen, finden Sie in meiner alternativen Antwort.
Dejay Clayton

1
Danke, obwohl das schon beim Betrachten offensichtlich sein sollte. Möglicherweise sind die Seitenfehler auf die Eingabegröße und die Anzahl der von Ihnen ausgeführten Iterationen zurückzuführen. Trotzdem gefällt mir deine Lösung.
JaredTS486

3

Dies ist eine weitaus schnellere Variante des Ansatzes von JaredTS486 , bei dem native Bash-Funktionen (einschließlich Bash-Versionen <4.0) verwendet werden, um seinen Ansatz zu optimieren.

Ich habe 1.000 Iterationen dieses Ansatzes für eine kleine Zeichenfolge (25 Zeichen) und eine größere Zeichenfolge (445 Zeichen) zeitlich festgelegt, sowohl für Konvertierungen in Klein- als auch in Großbuchstaben. Da die Testzeichenfolgen überwiegend in Kleinbuchstaben geschrieben sind, sind Konvertierungen in Kleinbuchstaben im Allgemeinen schneller als in Großbuchstaben.

Ich habe meinen Ansatz mit mehreren anderen Antworten auf dieser Seite verglichen, die mit Bash 3.2 kompatibel sind. Mein Ansatz ist weitaus leistungsfähiger als die meisten hier dokumentierten Ansätze und sogar schneller als trin einigen Fällen.

Hier sind die Timing-Ergebnisse für 1.000 Iterationen mit 25 Zeichen:

Timing-Ergebnisse für 1.000 Iterationen von 445 Zeichen (bestehend aus dem Gedicht "The Robin" von Witter Bynner):

  • 2s für meine Herangehensweise an Kleinbuchstaben; 12s für Großbuchstaben
  • 4s für trKleinbuchstaben; 4s für Großbuchstaben
  • 20er Jahre für Orwellophiles Herangehensweise an Kleinbuchstaben; 29s für Großbuchstaben
  • 75s für Ghostdog74s Herangehensweise an Kleinbuchstaben; 669s für Großbuchstaben. Es ist interessant festzustellen, wie dramatisch der Leistungsunterschied zwischen einem Test mit vorherrschenden Übereinstimmungen und einem Test mit vorherrschenden Fehlern ist
  • 467s für den Ansatz des Technosaurus in Kleinbuchstaben; 449s für Großbuchstaben
  • 660er Jahre für JaredTS486s Herangehensweise an Kleinbuchstaben; 660er für Großbuchstaben. Es ist interessant festzustellen, dass dieser Ansatz in Bash zu kontinuierlichen Seitenfehlern (Speicheraustausch) führte

Lösung:

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

Der Ansatz ist einfach: Während in der Eingabezeichenfolge noch Großbuchstaben vorhanden sind, suchen Sie den nächsten und ersetzen Sie alle Instanzen dieses Buchstabens durch seine Kleinbuchstabenvariante. Wiederholen, bis alle Großbuchstaben ersetzt sind.

Einige Leistungsmerkmale meiner Lösung:

  1. Verwendet nur integrierte Shell-Dienstprogramme, wodurch der Aufwand für das Aufrufen externer Binärdienstprogramme in einem neuen Prozess vermieden wird
  2. Vermeidet Unterschalen, die Leistungseinbußen verursachen
  3. Verwendet Shell-Mechanismen, die kompiliert und für die Leistung optimiert sind, z. B. das Ersetzen globaler Zeichenfolgen innerhalb von Variablen, das Trimmen von Variablensuffixen sowie das Suchen und Abgleichen von Regex. Diese Mechanismen sind weitaus schneller als das manuelle Durchlaufen von Zeichenfolgen
  4. Schleift nur die Häufigkeit, die für die Anzahl der zu konvertierenden eindeutigen übereinstimmenden Zeichen erforderlich ist. Zum Konvertieren einer Zeichenfolge mit drei verschiedenen Großbuchstaben in Kleinbuchstaben sind beispielsweise nur drei Schleifeniterationen erforderlich. Für das vorkonfigurierte ASCII-Alphabet beträgt die maximale Anzahl von Schleifeniterationen 26
  5. UCSund LCSkann mit zusätzlichen Zeichen erweitert werden

2

Speichern der transformierten Zeichenfolge in einer Variablen. Das Folgende hat bei mir funktioniert - $SOURCE_NAMEzu$TARGET_NAME

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

1

Einfacher Weg

echo "Hi all" | awk '{ print tolower($0); }'
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.