Hoe converteer je een string naar kleine letters in Bash?

Is er een manier om bashte converteren een tekenreeks in een tekenreeks in kleine letters?

Als ik bijvoorbeeld het volgende heb:

a="Hi all"

Ik wil het converteren naar:

"hi all"

Antwoord 1, autoriteit 100%

Er zijn verschillende manieren:

POSIX-standaard

tr

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

AWK

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

Niet-POSIX

U kunt met de volgende voorbeelden te maken krijgen met overdraagbaarheidsproblemen:

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

Opmerking: YMMV op deze. Werkt niet voor mij (GNU bash versie 4.2.46 en 4.0.33 (en hetzelfde gedrag 2.05b.0 maar nocasematch is niet geïmplementeerd)) zelfs met het gebruik van shopt -u nocasematch;. Als u die nocasematch uitschakelt, komt [[ “fooBaR” == “FOObar” ]] overeen met OK MAAR binnen de case wordt vreemd genoeg [b-z] onjuist vergeleken door [A-Z]. Bash is in de war door de dubbel-negatief (“unsetting nocasematch”)! 🙂


Antwoord 2, autoriteit 19%

In Bash 4:

Naar kleine letters

$ 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

Naar hoofdletters

$ 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 (niet gedocumenteerd, maar optioneel configureerbaar tijdens het compileren)

$ 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

Capitalize (niet gedocumenteerd, maar optioneel configureerbaar tijdens het compileren)

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

Titelgeval:

$ 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

Gebruik +om een +-kenmerk uit te schakelen. Bijvoorbeeld, declare +c string. Dit heeft invloed op volgende toewijzingen en niet op de huidige waarde.

De +opties veranderen het attribuut van de variabele, maar niet de inhoud. De hertoewijzingen in mijn voorbeelden werken de inhoud bij om de wijzigingen te tonen.

Bewerken:

“Toggle eerste teken voor woord” toegevoegd (${var~}) zoals voorgesteld door ghostdog74.

Bewerken:tilde-gedrag gecorrigeerd om overeen te komen met Bash 4.3.


Antwoord 3, autoriteit 5%

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

Antwoord 4, autoriteit 4%

tr:

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

AWK:

{ print tolower($0) }

sed:

y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/

Antwoord 5, autoriteit 2%

Ik weet dat dit een ouderwets bericht is, maar ik heb dit antwoord voor een andere site gemaakt, dus ik dacht ik post het hier:

BOVENSTE -> lager:
gebruik python:

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

Of Robijn:

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

Of Perl:

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

Of PHP:

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

Of Awk:

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

Of Sed:

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

Of Bash 4:

b=${a,,}

Of NodeJS:

b=`node -p "\"$a\".toLowerCase()"`

U kunt ook ddgebruiken:

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

lager -> BOVENSTE:

gebruik python:

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

Of Robijn:

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

of perl:

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

of php:

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

of awk:

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

of sed:

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

of bash 4:

b=${a^^}

of nodejs:

b=`node -p "\"$a\".toUpperCase()"`

U kunt ook dd:

gebruiken

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

Ook wanneer u ‘Shell’ zegt, ik neem aan dat u bedoelt Bash, maar als u zshkunt gebruiken, is het net zo eenvoudig als

b=$a:l

Voor kleine letters en

b=$a:u

voor hoofdletters.


Antwoord 6

in zsh:

echo $a:u

Ik hou van ZSH!


Antwoord 7

GNU gebruiken sed:

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

Voorbeeld:

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

Antwoord 8

Pre Bash 4.0

Bash Verlaag de hoofdletters van een tekenreeks en wijs deze toe aan variabele

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

Antwoord 9

U kunt dit proberen

s="Hello World!" 
echo $s  # Hello World!
a=${s,,}
echo $a  # hello world!
b=${s^^}
echo $b  # HELLO WORLD!

ref : http://wiki.workassis .com/shell-script-convert-text-to-lowercase-and-uppercase/


Antwoord 10

Voor een standaard shell (zonder bashisms) die alleen ingebouwde elementen gebruikt:

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

En voor hoofdletters:

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

Antwoord 11

In bash 4 kunt u gebruik maken

Voorbeeld:

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

Antwoord 12

bash 5.1 biedt een eenvoudige manier om dit met de Lparameter transformatie:

${var@L}

Dus je kunt bijvoorbeeld zeggen:

$ v="heLLo"
$ echo "${v@L}"
hello

U kunt ook hoofdletters uitvoeren met U:

$ v="hello"
$ echo "${v@U}"
HELLO

en hoofdletter de eerste letter met U:

$ v="hello"
$ echo "${v@U}"
HELLO

Antwoord 13

Reguliere expressie

Ik zou graag krediet willen nemen voor het commando dat ik wil delen, maar de waarheid is dat ik het heb verkregen voor mijn eigen gebruik van http: / /commandlinefu.com . Het heeft het voordeel dat als u cdnaar elke map binnen uw eigen woningmap is, die het ook is, alle bestanden en mappen in kleine letters recursief zal wijzigen, voorzichtig. Het is een briljante opdrachtregel-fix en vooral handig voor die multiteuses van albums die u op uw drive hebt opgeslagen.

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

U kunt een map opgeven in plaats van de punt (.) Na de vondst die de huidige map of het volledige pad aangeeft.

Ik hoop dat deze oplossing nuttig zal zijn. Het enige dat dit commando niet doet, is spaties vervangen door onderstrepingstekens – ach, een andere keer misschien.


Antwoord 14

Hoofdlettergebruik wordt alleen voor alfabetten omgezet. Dit zou dus netjes moeten werken.

Ik concentreer me op het omzetten van alfabetten tussen a-z van hoofdletters naar kleine letters. Alle andere tekens moeten gewoon in stdout worden afgedrukt zoals het is…

Converteert alle tekst in pad/naar/bestand/bestandsnaam binnen a-z bereik naar A-Z

Voor het converteren van kleine letters naar hoofdletters

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

Voor het omzetten van hoofdletters naar kleine letters

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

Bijvoorbeeld

bestandsnaam:

my name is xyz

wordt geconverteerd naar:

my name is xyz

Voorbeeld 2:

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

Voorbeeld 3:

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

Antwoord 15

Veel antwoorden met externe programma’s, die niet echt Bashgebruiken.

Als je weet dat je Bash4 beschikbaar hebt, moet je gewoon de notatie ${VAR,,}gebruiken (het is gemakkelijk en cool). Voor Bash voor 4 (mijn Mac gebruikt bijvoorbeeld nog steeds Bash 3.2). Ik heb de gecorrigeerde versie van het antwoord van @ghostdog74 gebruikt om een meer draagbare versie te maken.

Eentje die je lowercase 'my STRING'kunt noemen en een kleine versie kunt krijgen. Ik heb opmerkingen gelezen over het instellen van het resultaat op een var, maar dat is niet echt draagbaar in Bash, omdat we geen strings kunnen retourneren. Printen is de beste oplossing. Makkelijk vast te leggen met iets als var="$(lowercase $str)".

Hoe dit werkt

De manier waarop dit werkt is door de ASCII integer-representatie van elke char op te halen met printfen dan adding 32if upper-to->lower, of subtracting 32als lower-to->upper. Gebruik vervolgens opnieuw printfom het getal weer om te zetten naar een char. Van 'A' -to-> 'a'we hebben een verschil van 32 tekens.

printfgebruiken om uit te leggen:

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

97 - 65 = 32

En dit is de werkende versie met voorbeelden.
Let op de opmerkingen in de code, omdat ze veel dingen uitleggen:

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

En de resultaten na het uitvoeren van dit:

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

Dit zou echter alleen moeten werken voor ASCII-tekens.

Voor mij is het prima, omdat ik weet dat ik er alleen ASCII-tekens aan zal doorgeven.
Ik gebruik dit bijvoorbeeld voor enkele hoofdletterongevoelige CLI-opties.


Antwoord 16

Eenvoudige manier

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

Antwoord 17

Als je v4 gebruikt, is dit ingebakken. Zo niet, dan is hier een eenvoudige, breed toepasbareoplossing. Andere antwoorden (en opmerkingen) in deze thread waren heel nuttig bij het maken van de onderstaande code.

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

Opmerkingen:

  • Doen: a="Hi All"en dan: lcase adoet hetzelfde als: a=$( echolcase "Hi All" )
  • In de lcase-functie zorgt het gebruik van ${!1//\'/"'\''"}in plaats van ${!1}ervoor dat dit werkt zelfs als de string aanhalingstekens heeft.

Antwoord 18

Dit is een veel snellere variant van de JaredTS486’s approachdie gebruikmaakt van native Bash-mogelijkheden (inclusief Bash versies <4.0) om zijn aanpak te optimaliseren.

Ik heb 1000 iteraties van deze aanpak voor een kleine string (25 tekens) en een grotere reeks (445 tekens), zowel voor kleine letters als in hoofdletters). Aangezien de teststrings overwegend kleine letters zijn, zijn conversies naar kleine letters in het algemeen sneller dan in hoofdletters.

Ik heb mijn aanpak vergeleken met verschillende andere antwoorden op deze pagina die compatibel is met bash 3.2. Mijn aanpak is veel belangrijker dan de meeste benaderingen die hier worden gedocumenteerd en is nog sneller dan trin verschillende gevallen.

Hier zijn de timingresultaten voor 1.000 iteraties van 25 tekens:

Timingresultaten voor 1.000 iteraties van 445 tekens (bestaande uit het gedicht “The Robin” door Witter Bynner):

  • 2S voor mijn benadering van kleine letters; 12s voor hoofdletters
  • 4s voor trnaar kleine letters; 4s voor hoofdletters
  • 20s voor orwellophile’s aanpak naar kleine letters; 29s voor hoofdletters
  • 75s voor ghostdog74’sbenadering van kleine letters; 669s voor hoofdletters. Het is interessant om op te merken hoe dramatisch het prestatieverschil is tussen een test met overheersende overeenkomsten versus een test met overheersende missers
  • 467s voor technosaurus’ approachnaar kleine letters; 449s voor hoofdletters
  • 660s voor JaredTS486’s approachnaar kleine letters; 660s voor hoofdletters. Het is interessant om op te merken dat deze aanpak continue paginafouten (memory swapping) in Bash genereerde

Oplossing:

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

De aanpak is eenvoudig: terwijl de invoerreeks nog hoofdletters bevat, zoek de volgende en vervang alle instanties van die letter door de kleine lettervariant. Herhaal dit totdat alle hoofdletters zijn vervangen.

Enkele prestatiekenmerken van mijn oplossing:

  1. Gebruikt alleen in de shell ingebouwde hulpprogramma’s, waardoor de overhead van het aanroepen van externe binaire hulpprogramma’s in een nieuw proces wordt vermeden
  2. Vermijdt sub-shells, die prestatiestraffen opleveren
  3. Gebruikt shell-mechanismen die zijn gecompileerd en geoptimaliseerd voor prestaties, zoals globale vervanging van strings binnen variabelen, trimmen van variabele achtervoegsels en zoeken en matchen met regex. Deze mechanismen zijn veel sneller dan handmatig herhalen via strings
  4. Loopt alleen het aantal keren dat nodig is voor het aantal unieke overeenkomende tekens dat moet worden geconverteerd. Als u bijvoorbeeld een tekenreeks met drie verschillende hoofdletters naar kleine letters wilt converteren, zijn slechts 3 lus-iteraties nodig. Voor het vooraf geconfigureerde ASCII-alfabet is het maximale aantal lusiteraties 26
  5. UCSen LCSkunnen worden aangevuld met extra tekens

Antwoord 19

Voor Bash-versies ouder dan 4.0 zou deze versie het snelst moeten zijn (omdat het geen fork /execalle commando’s):

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’s antwoordhad potentieel ook, hoewel het voor mij wel goed liep.


Antwoord 20

Ondanks hoe oud deze vraag is en vergelijkbaar met dit antwoord door Technosaurus . Ik had een harde tijd vinden van een oplossing die overdraagbaar is tussen de meeste platforms was (die ik gebruik) alsook oudere versies van bash. Ik heb ook al gefrustreerd met arrays, functies en het gebruik van prints, echo’s en tijdelijke bestanden triviale variabelen op te halen. Dit werkt heel goed voor mij tot nu toe dacht ik dat ik zou delen.
Mijn belangrijkste testen omgevingen zijn:

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

Eenvoudige C-stijl voor lus te herhalen door de strijkers.
Voor de lijn hieronder als je niet iets als dit eerder gezien
dit is waar ik dit geleerd. In dit geval de lijn controleert of de char $ {ingang: $ i: 1} (kleine letters) bestaat in ingang en zo vervangen door het gegeven char $ {UCS: $ j: 1} (hoofdletters) en opslaat terug naar ingang.

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

Antwoord 21

Om de getransformeerde string in een variabele op te slaan. Volgend werkte voor mij –
$SOURCE_NAMEnaar $TARGET_NAME

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

Other episodes