web-dev-qa-db-fra.com

Comment convertir une chaîne en minuscule dans Bash?

Existe-t-il un moyen dans bash de convertir une chaîne en chaîne en minuscule?

Par exemple, si j'ai:

a="Hi all"

Je veux le convertir en:

"hi all"
1008
assassin

Les sont de différentes manières:

standard POSIX

tr

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

AWK

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

Non-POSIX

Vous pouvez rencontrer des problèmes de portabilité avec les exemples suivants:

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

Dans Bash 4:

En minuscule

$ 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

À majuscule

$ 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

Basculer (non documenté, mais éventuellement configurable à la compilation)

$ 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

Capitaliser (non documenté, mais éventuellement configurable à la compilation)

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

Titre case:

$ 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

Pour désactiver un attribut declare, utilisez +. Par exemple, declare +c string. Cela affecte les affectations suivantes et non la valeur actuelle.

Les options declare changent l'attribut de la variable, mais pas le contenu. Les réaffectations de mes exemples mettent à jour le contenu pour afficher les modifications.

Modifier:

Ajout de "bascule le premier caractère par Word" (${var~}) comme suggéré par ghostdog74 .

Edit: Correction du comportement du tilde pour correspondre à 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

Je sais que c’est un article ancien, mais j’ai fait cette réponse pour un autre site, alors j’ai pensé le poster ici:

UPPER -> lower : Utilisez python:

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

Ou Ruby:

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

Ou Perl (probablement mon préféré):

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

Ou PHP:

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

Ou Awk:

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

Ou Sed:

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

Ou Bash 4:

b=${a,,}

Ou NodeJS si vous l'avez (et êtes un peu cinglé ...):

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

Vous pouvez aussi utiliser dd (mais pas moi!):

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

inférieur -> UPPER :

utilisez python:

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

Ou Ruby:

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

Ou Perl (probablement mon préféré):

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

Ou PHP:

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

Ou Awk:

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

Ou Sed:

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

Ou Bash 4:

b=${a^^}

Ou NodeJS si vous l'avez (et êtes un peu cinglé ...):

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

Vous pouvez aussi utiliser dd (mais pas moi!):

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

Aussi, quand vous dites 'Shell', je suppose que vous voulez dire bash mais si vous pouvez utiliser zsh c'est aussi simple que

b=$a:l

pour les minuscules et

b=$a:u

pour les majuscules.

38
nettux

En zsh:

echo $a:u

Je dois aimer zsh!

26
Scott Smedley

Utilisation de GNU sed:

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

Exemple:

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

Pour un shell standard (sans bashismes) utilisant uniquement les fonctions intégrées:

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

Et pour les majuscules:

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

Pre Bash 4.0

Bash Diminue la casse d'une chaîne et affecte une variable

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

echo "$VARIABLE"
10
hawkeye126

Dans bash 4, vous pouvez utiliser la composition

Exemple:

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

Expression régulière

J'aimerais prendre le crédit de la commande que je souhaite partager, mais la vérité est que je l’ai obtenue pour mon usage personnel à partir de http://commandlinefu.com . Il a l'avantage que si vous cd dans n'importe quel répertoire de votre propre dossier de base, tous les fichiers et dossiers en minuscules seront modifiés de manière récursive, veuillez utiliser ce paramètre avec prudence. C’est un correctif de ligne de commande brillant et particulièrement utile pour les multitudes d’albums que vous avez stockés sur votre lecteur.

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

Vous pouvez spécifier un répertoire à la place du point (.) Après la recherche, qui désigne le répertoire en cours ou le chemin complet.

J'espère que cette solution s'avère utile, mais cette commande ne permet pas de remplacer les espaces par des traits de soulignement - peut-être une autre fois.

7
Derek Shaw

Tu peux essayer ça

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.workassis.com/Shell-script-convert-text-to-lowercase-and-uppercase/

6
Bikesh M Annur

En dépit de l'âge de cette question et semblable à cette réponse de technosaurus . J'ai eu du mal à trouver une solution portable sur la plupart des plateformes (That I Use) ainsi que sur les anciennes versions de bash. J'ai également été frustré par les tableaux, les fonctions et l'utilisation des impressions, des échos et des fichiers temporaires pour récupérer des variables triviales. Cela fonctionne très bien pour moi jusqu'à présent, je pensais partager . Mes principaux environnements de test sont: 

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

Simple C-style for loop pour parcourir les chaînes . Pour la ligne ci-dessous si vous n'avez jamais rien vu de tel auparavant c'est ici que j'ai appris cela . Dans ce cas, la ligne vérifie si le caractère $ {input: $ i: 1} (minuscule) existe en entrée et, le cas échéant, le remplace par le caractère donné $ {ucs: $ j: 1} (majuscule) et le stocke. retour en entrée.

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

Pour les versions de Bash antérieures à 4.0, cette version devrait être la plus rapide (car elle ne prend pas fork/exec aucune commande):

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

La réponse de technosaurus avait aussi du potentiel, même si elle a fonctionné correctement pour moi.

3
Orwellophile

Si vous utilisez v4, c’est cuit au four . Sinon, voici une solution simple, largement applicable. D'autres réponses (et commentaires) sur ce fil ont été très utiles pour créer le code ci-dessous.

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

Notes:

  • Faire: a="Hi All" et ensuite: lcase a fera la même chose que: a=$( echolcase "Hi All" )
  • Dans la fonction lcase, l'utilisation de ${!1//\'/"'\''"} au lieu de ${!1} permet que cela fonctionne même lorsque la chaîne contient des guillemets.
3
Stephen M. Harris

Beaucoup de réponses utilisent des programmes externes, qui n'utilisent pas vraiment Bash.

Si vous savez que vous aurez Bash4 disponible, vous devriez vraiment utiliser la notation ${VAR,,} (c’est facile et cool). Pour Bash avant 4 (Mon Mac utilise toujours Bash 3.2 par exemple). J'ai utilisé la version corrigée de la réponse de @ ghostdog74 pour créer une version plus portable.

Celui que vous pouvez appeler lowercase 'my STRING' et obtenir une version minuscule. J'ai lu des commentaires sur la définition du résultat dans une variable, mais ce n'est pas vraiment portable dans Bash, car nous ne pouvons pas renvoyer de chaînes. L'imprimer est la meilleure solution. Facile à capturer avec quelque chose comme var="$(lowercase $str)"

Comment ça marche

Cela fonctionne en obtenant la représentation ASCII entière de chaque caractère avec printf, puis adding 32 si upper-to->lower ou subtracting 32 si lower-to->upper. Utilisez ensuite à nouveau printf pour reconvertir le nombre en caractère. De 'A' -to-> 'a' nous avons une différence de 32 caractères.

Utiliser printf pour expliquer:

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

97 - 65 = 32

Et ceci est la version de travail avec des exemples.
Veuillez noter les commentaires dans le code, car ils expliquent beaucoup de choses:

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

Et les résultats après avoir exécuté ceci:

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

Ceci ne devrait fonctionner que pour les caractères ASCII bien que

Pour moi, ça va, puisque je sais que je ne lui transmettrai que des caractères ASCII.
J'utilise ceci pour certaines options CLI qui respectent la casse, par exemple.

3
Gus Neves

Si vous aimez python et avez la possibilité d'installer un nouveau package python, vous pouvez essayer cet utilitaire python .

# install pythonp
$ pip install pythonp

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

La conversion de casse est effectuée uniquement pour les alphabets. Donc, cela devrait fonctionner proprement.

Je me concentre sur la conversion des alphabets entre a-z de majuscules à minuscules. Tous les autres caractères doivent simplement être imprimés dans stdout tels quels.

Convertit tout le texte dans path/to/file/filename dans la plage a-z en A-Z

Pour convertir les minuscules en majuscules

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

Pour convertir des majuscules en minuscules

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

Par exemple,

nom de fichier:

my name is xyz

se convertit en:

MY NAME IS XYZ

Exemple 2:

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

Exemple 3:

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

Pour stocker la chaîne transformée dans une variable. Suivre a travaillé pour moi -$SOURCE_NAME à $TARGET_NAME 

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

Il s’agit d’une variante beaucoup plus rapide de l’approche de JaredTS486 qui utilise les fonctionnalités natives de Bash (y compris les versions de Bash <4.0) pour optimiser son approche.

J'ai chronométré 1 000 itérations de cette approche pour une petite chaîne (25 caractères) et une plus grande chaîne (445 caractères), pour les conversions minuscules et majuscules. Étant donné que les chaînes de test sont principalement en minuscules, les conversions en minuscules sont généralement plus rapides qu'en majuscules.

J'ai comparé mon approche avec plusieurs autres réponses sur cette page, compatibles avec Bash 3.2. Mon approche est beaucoup plus performante que la plupart des approches décrites ici et est même plus rapide que tr dans plusieurs cas.

Voici les résultats de minutage pour 1000 itérations de 25 caractères:

Résultats chronométrés pour 1 000 itérations de 445 caractères (comprenant le poème "The Robin" de Witter Bynner):

  • 2s pour mon approche en minuscule; 12s pour les majuscules
  • 4s pour tr à minuscule; 4s pour les majuscules
  • 20s pour l'approche d'Orwellophile en minuscule; 29s pour les majuscules
  • 75s pour ghostdog74's approche de minuscule; 669s pour les majuscules. Il est intéressant de noter à quel point la différence de performance est spectaculaire entre un test avec des matchs prédominants et un test avec des échecs prédominants.
  • 467s pour approche de technosaurus en minuscule; 449s pour les majuscules
  • 660s pour l'approche de JaredTS486 to minuscule; 660s pour les majuscules. Il est intéressant de noter que cette approche a généré des défauts de page continus (échange de mémoire) dans Bash.

Solution:

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

L’approche est simple: même s’il reste des lettres majuscules dans la chaîne d’entrée, recherchez la suivante et remplacez toutes les occurrences de cette lettre par sa variante minuscule. Répétez l'opération jusqu'à ce que toutes les lettres majuscules soient remplacées.

Quelques caractéristiques de performance de ma solution:

  1. Utilise uniquement les utilitaires intégrés à Shell, ce qui évite la surcharge d'invocation d'utilitaires binaires externes dans un nouveau processus
  2. Évite les sous-coquilles, qui encourent des pénalités de performance
  3. Utilise des mécanismes de shell compilés et optimisés pour améliorer les performances, tels que le remplacement global de chaînes dans les variables, la suppression de suffixe de variable et la recherche et la correspondance regex. Ces mécanismes sont beaucoup plus rapides que l'itération manuelle à l'aide de chaînes
  4. Boucle uniquement le nombre de fois requis par le nombre de caractères uniques uniques à convertir. Par exemple, convertir une chaîne comportant trois caractères majuscules différents en minuscules ne nécessite que 3 itérations de boucle. Pour l'alphabet ASCII préconfiguré, le nombre maximal d'itérations en boucle est de 26.
  5. UCS et LCS peuvent être complétés par des caractères supplémentaires
0
Dejay Clayton