How to convert a string to lower case in Bash?


How to convert a string to lower case in Bash?
Is there a way in bash to convert a string into a lower case string?
For example, if I have:
a="Hi all"
I want to convert it to:
"hi all"
19 Answers
19
The are various ways:
$ echo "$a" | tr '[:upper:]' '[:lower:]'
hi all
$ echo "$a" | awk 'print tolower($0)'
hi all
$ echo "$a,,"
hi all
$ echo "$a" | sed -e 's/(.*)/L1/'
hi all
# this also works:
$ sed -e 's/(.*)/L1/' <<< "$a"
hi all
$ echo "$a" | perl -ne 'print lc'
hi all
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
Am I missing something, or does your last example (in Bash) actually do something completely different? It works for "ABX", but if you instead make
word="Hi All"
like the other examples, it returns ha
, not hi all
. It only works for the capitalized letters and skips the already-lowercased letters.– jangosteve
Jan 14 '12 at 21:58
word="Hi All"
ha
hi all
Note that only the
tr
and awk
examples are specified in the POSIX standard.– Richard Hansen
Feb 3 '12 at 18:55
tr
awk
tr '[:upper:]' '[:lower:]'
will use the current locale to determine uppercase/lowercase equivalents, so it'll work with locales that use letters with diacritical marks.– Richard Hansen
Feb 3 '12 at 18:58
tr '[:upper:]' '[:lower:]'
How does one get the output into a new variable? Ie say I want the lowercased string into a new variable?
– Adam Parkin
Sep 25 '12 at 18:01
@Adam:
b="$(echo $a | tr '[A-Z]' '[a-z]')"
– Tino
Nov 14 '12 at 15:39
b="$(echo $a | tr '[A-Z]' '[a-z]')"
In Bash 4:
To lowercase
$ 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
To uppercase
$ 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 (undocumented, but optionally configurable at compile time)
$ 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 (undocumented, but optionally configurable at compile time)
$ string="a few words"
$ declare -c string
$ string=$string
$ echo "$string"
A few words
Title 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
To turn off a declare
attribute, use +
. For example, declare +c string
. This affects subsequent assignments and not the current value.
declare
+
declare +c string
The declare
options change the attribute of the variable, but not the contents. The reassignments in my examples update the contents to show the changes.
declare
Edit:
Added "toggle first character by word" ($var~
) as suggested by ghostdog74.
$var~
Edit: Corrected tilde behavior to match Bash 4.3.
there's also
$string~
– ghostdog74
Feb 15 '10 at 10:52
$string~
Quite bizzare, "^^" and ",," operators don't work on non-ASCII characters but "~~" does... So
string="łódź"; echo $string~~
will return "ŁÓDŹ", but echo $string^^
returns "łóDź". Even in LC_ALL=pl_PL.utf-8
. That's using bash 4.2.24.– Hubert Kario
Jul 12 '12 at 16:48
string="łódź"; echo $string~~
echo $string^^
LC_ALL=pl_PL.utf-8
@HubertKario: That's weird. It's the same for me in Bash 4.0.33 with the same string in
en_US.UTF-8
. It's a bug and I've reported it.– Dennis Williamson
Jul 12 '12 at 18:20
en_US.UTF-8
@HubertKario: Try
echo "$string" | tr '[:lower:]' '[:upper:]'
. It will probably exhibit the same failure. So the problem is at least partly not Bash's.– Dennis Williamson
Jul 13 '12 at 0:44
echo "$string" | tr '[:lower:]' '[:upper:]'
@HubertKario: The Bash maintainer has acknowledged the bug and stated that it will be fixed in the next release.
– Dennis Williamson
Jul 14 '12 at 14:27
echo "Hi All" | tr "[:upper:]" "[:lower:]"
+1 for not assuming english
– Richard Hansen
Feb 3 '12 at 19:00
@RichardHansen:
tr
doesn't work for me for non-ACII characters. I do have correct locale set and locale files generated. Have any idea what could I be doing wrong?– Hubert Kario
Jul 12 '12 at 16:56
tr
FYI: This worked on Windows/Msys. Some of the other suggestions did not.
– wasatchwizard
Oct 23 '14 at 16:42
a="$(tr [A-Z] [a-z] <<< "$a")"
print tolower($0)
y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
+1
a="$(tr [A-Z] [a-z] <<< "$a")"
looks easiest to me. I am still a beginner...– Sandeepan Nath
Feb 2 '11 at 11:12
a="$(tr [A-Z] [a-z] <<< "$a")"
I strongly recommend the
sed
solution; I've been working in an environment that for some reason doesn't have tr
but I've yet to find a system without sed
, plus a lot of the time I want to do this I've just done something else in sed
anyway so can chain the commands together into a single (long) statement.– Haravikk
Oct 19 '13 at 12:54
sed
tr
sed
sed
The bracket expressions should be quoted. In
tr [A-Z] [a-z] A
, the shell may perform filename expansion if there are filenames consisting of a single letter or nullgob is set. tr "[A-Z]" "[a-z]" A
will behave properly.– Dennis
Nov 6 '13 at 19:49
tr [A-Z] [a-z] A
tr "[A-Z]" "[a-z]" A
@CamiloMartin it's a BusyBox system where I'm having that problem, specifically Synology NASes, but I've encountered it on a few other systems too. I've been doing a lot of cross-platform shell scripting lately, and with the requirement that nothing extra be installed it makes things very tricky! However I've yet to encounter a system without
sed
– Haravikk
Jun 15 '14 at 10:51
sed
Note that
tr [A-Z] [a-z]
is incorrect in almost all locales. for example, in the en-US
locale, A-Z
is actually the interval AaBbCcDdEeFfGgHh...XxYyZ
.– fuz
Jan 31 '16 at 14:54
tr [A-Z] [a-z]
en-US
A-Z
AaBbCcDdEeFfGgHh...XxYyZ
I know this is an oldish post but I made this answer for another site so I thought I'd post it up here:
UPPER -> lower:
use python:
b=`echo "print '$a'.lower()" | python`
Or Ruby:
b=`echo "print '$a'.downcase" | ruby`
Or Perl (probably my favorite):
b=`perl -e "print lc('$a');"`
Or PHP:
b=`php -r "print strtolower('$a');"`
Or Awk:
b=`echo "$a" | awk ' print tolower($1) '`
Or Sed:
b=`echo "$a" | sed 's/./L&/g'`
Or Bash 4:
b=$a,,
Or NodeJS if you have it (and are a bit nuts...):
b=`echo "console.log('$a'.toLowerCase());" | node`
You could also use dd
(but I wouldn't!):
dd
b=`echo "$a" | dd conv=lcase 2> /dev/null`
lower -> UPPER:
use python:
b=`echo "print '$a'.upper()" | python`
Or Ruby:
b=`echo "print '$a'.upcase" | ruby`
Or Perl (probably my favorite):
b=`perl -e "print uc('$a');"`
Or PHP:
b=`php -r "print strtoupper('$a');"`
Or Awk:
b=`echo "$a" | awk ' print toupper($1) '`
Or Sed:
b=`echo "$a" | sed 's/./U&/g'`
Or Bash 4:
b=$a^^
Or NodeJS if you have it (and are a bit nuts...):
b=`echo "console.log('$a'.toUpperCase());" | node`
You could also use dd
(but I wouldn't!):
dd
b=`echo "$a" | dd conv=ucase 2> /dev/null`
Also when you say 'shell' I'm assuming you mean bash
but if you can use zsh
it's as easy as
bash
zsh
b=$a:l
for lower case and
b=$a:u
for upper case.
Neither the sed command nor the bash command worked for me.
– JESii
May 28 '15 at 21:42
@JESii both work for me upper -> lower and lower-> upper. I'm using sed 4.2.2 and Bash 4.3.42(1) on 64bit Debian Stretch.
– nettux443
Nov 20 '15 at 14:33
Hi, @nettux443... I just tried the bash operation again and it still fails for me with the error message "bad substitution". I'm on OSX using homebrew's bash: GNU bash, version 4.3.42(1)-release (x86_64-apple-darwin14.5.0)
– JESii
Nov 21 '15 at 17:34
Do not use! All of the examples which generate a script are extremely brittle; if the value of
a
contains a single quote, you have not only broken behavior, but a serious security problem.– tripleee
Jan 16 '16 at 11:45
a
I like the sed solution the most, since sed is always ubiquitous.
– Dudi Boy
Dec 9 '17 at 13:47
In zsh:
echo $a:u
Gotta love zsh!
or $a:l for lower case conversion
– Scott Smedley
Jan 27 '11 at 5:39
Add one more case:
echo $(C)a #Upcase the first char only
– biocyberman
Jul 24 '15 at 23:26
echo $(C)a #Upcase the first char only
Using GNU sed
:
sed
sed 's/.*/L&/'
Example:
$ foo="Some STRIng";
$ foo=$(echo "$foo" | sed 's/.*/L&/')
$ echo "$foo"
some string
For a standard shell (without bashisms) using only builtins:
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"
And for upper case:
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"
I wonder if you didn't let some bashism in this script, as it's not portable on FreeBSD sh: $1:$...: Bad substitution
– Dereckson
Nov 23 '14 at 19:52
Indeed; substrings with
$var:1:1
are a Bashism.– tripleee
Apr 14 '15 at 7:09
$var:1:1
This approach has pretty bad performance metrics. See my answer for metrics.
– Dejay Clayton
24 mins ago
Pre Bash 4.0
Bash Lower the Case of a string and assign to variable
VARIABLE=$(echo "$VARIABLE" | tr '[:upper:]' '[:lower:]')
echo "$VARIABLE"
No need for
echo
and pipes: use $(tr '[:upper:]' '[:lower:]' <<<"$VARIABLE")
– Tino
Dec 11 '15 at 16:23
echo
$(tr '[:upper:]' '[:lower:]' <<<"$VARIABLE")
@Tino The here string is also not portable back to really old versions of Bash; I believe it was introduced in v3.
– tripleee
Jan 16 '16 at 12:28
@tripleee You are right, it was introduced in bash-2.05b - however that's the oldest bash I was able to find on my systems
– Tino
Jan 17 '16 at 14:28
I would like to take credit for the command I wish to share but the truth is I obtained it for my own use from http://commandlinefu.com. It has the advantage that if you cd
to any directory within your own home folder that is it will change all files and folders to lower case recursively please use with caution. It is a brilliant command line fix and especially useful for those multitudes of albums you have stored on your drive.
cd
find . -depth -exec rename 's/(.*)/([^/]*)/$1/L$2/' ;
You can specify a directory in place of the dot(.) after the find which denotes current directory or full path.
I hope this solution proves useful the one thing this command does not do is replace spaces with underscores - oh well another time perhaps.
thanks for commandlinefu.com
– Wadih M.
Nov 29 '11 at 1:31
This didn't work for me for whatever reason, though it looks fine. I did get this to work as an alternative though: find . -exec /bin/bash -c 'mv `tr [A-Z] [a-z] <<< `' ;
– John Rix
Jun 26 '13 at 15:58
This needs
prename
from perl
: dpkg -S "$(readlink -e /usr/bin/rename)"
gives perl: /usr/bin/prename
– Tino
Dec 11 '15 at 16:27
prename
perl
dpkg -S "$(readlink -e /usr/bin/rename)"
perl: /usr/bin/prename
In bash 4 you can use typeset
Example:
A="HELLO WORLD"
typeset -l A=$A
You can try this
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/
If using v4, this is baked-in. If not, here is a simple, widely applicable solution. Other answers (and comments) on this thread were quite helpful in creating the code below.
# 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//'/"'''"
Notes:
a="Hi All"
lcase a
a=$( echolcase "Hi All" )
$!1//'/"'''"
$!1
For Bash versions earlier than 4.0, this version should be fastest (as it doesn't fork/exec any commands):
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 answer had potential too, although it did run properly for mee.
Not bad! For an analysis of the performance of this approach, please see my answer for metrics.
– Dejay Clayton
23 mins ago
In spite of how old this question is and similar to this answer by technosaurus. I had a hard time finding a solution that was portable across most platforms (That I Use) as well as older versions of bash. I have also been frustrated with arrays, functions and use of prints, echos and temporary files to retrieve trivial variables. This works very well for me so far I thought I would share.
My main testing environments are:
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 to iterate through the strings.
For the line below if you have not seen anything like this before
this is where I learned this. In this case the line checks if the char $input:$i:1 (lower case) exists in input and if so replaces it with the given char $ucs:$j:1 (upper case) and stores it back into input.
input="$input/$input:$i:1/$ucs:$j:1"
This is wildly inefficient, looping 650 times in your example above, and taking 35 seconds to execute 1000 invocations on my machine. For an alternative that loops just 11 times and takes less than 5 seconds to execute 1000 invocations, see my alternative answer.
– Dejay Clayton
6 hours ago
Many answers using external programs, which is not really using Bash
.
Bash
If you know you will have Bash4 available you should really just use the $VAR,,
notation (it is easy and cool). For Bash before 4 (My Mac still uses Bash 3.2 for example). I used the corrected version of @ghostdog74 's answer to create a more portable version.
$VAR,,
One you can call lowercase 'my STRING'
and get a lowercase version. I read comments about setting the result to a var, but that is not really portable in Bash
, since we can't return strings. Printing it is the best solution. Easy to capture with something like var="$(lowercase $str)"
.
lowercase 'my STRING'
Bash
var="$(lowercase $str)"
How this works
The way this works is by getting the ASCII integer representation of each char with printf
and then adding 32
if upper-to->lower
, or subtracting 32
if lower-to->upper
. Then use printf
again to convert the number back to a char. From 'A' -to-> 'a'
we have a difference of 32 chars.
printf
adding 32
upper-to->lower
subtracting 32
lower-to->upper
printf
'A' -to-> 'a'
Using printf
to explain:
printf
$ printf "%dn" "'a"
97
$ printf "%dn" "'A"
65
97 - 65 = 32
97 - 65 = 32
And this is the working version with examples.
Please note the comments in the code, as they explain a lot of stuff:
#!/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
And the results after running this:
$ ./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!
This should only work for ASCII characters though.
For me it is fine, since I know I will only pass ASCII chars to it.
I am using this for some case-insensitive CLI options, for example.
Converting case is done for alphabets only. So, this should work neatly.
I am focusing on converting alphabets between a-z from upper case to lower case. Any other characters should just be printed in stdout as it is...
Converts the all text in path/to/file/filename within a-z range to A-Z
For converting lower case to upper case
cat path/to/file/filename | tr 'a-z' 'A-Z'
For converting from upper case to lower case
cat path/to/file/filename | tr 'A-Z' 'a-z'
For example,
filename:
my name is xyz
gets converted to:
MY NAME IS XYZ
Example 2:
echo "my name is 123 karthik" | tr 'a-z' 'A-Z'
# Output:
# MY NAME IS 123 KARTHIK
Example 3:
echo "my name is 123 &&^&& #@$#@%%& kAR2~thik" | tr 'a-z' 'A-Z'
# Output:
# MY NAME IS 123 &&^&& #@0@%%& KAR2~THIK
To store the transformed string into a variable. Following worked for me -$SOURCE_NAME
to $TARGET_NAME
$SOURCE_NAME
$TARGET_NAME
TARGET_NAME="`echo $SOURCE_NAME | tr '[:upper:]' '[:lower:]'`"
This is a far faster variation of JaredTS486's approach that uses native Bash capabilities (including Bash versions <4.0) to optimize his approach.
I've timed 1,000 iterations of this approach for a small string (25 characters) and a larger string (445 characters), both for lowercase and uppercase conversions. Since the test strings are predominantly lowercase, conversions to lowercase are generally faster than to uppercase.
I've compared my approach with several other answers on this page that are compatible with Bash 3.2. My approach is far more performant than most approaches documented here, and is even faster than tr
in several cases.
tr
Here are the timing results for 1,000 iterations of 25 characters:
tr
Timing results for 1,000 iterations of 445 characters (consisting of the poem "The Robin" by Witter Bynner):
tr
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"
The approach is simple: while the input string has any remaining uppercase letters present, find the next one, and replace all instances of that letter with its lowercase variant. Repeat until all uppercase letters are replaced.
Some performance characteristics of my solution:
UCS
LCS
Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).
Would you like to answer one of these unanswered questions instead?
See also: stackoverflow.com/questions/11392189
– dreftymac
Mar 29 at 16:04