140

I have been searching to find a way to convert a string value from uppercase to lowercase. All the search results show approaches of using the tr command.

The problem with the tr command is that I am able to get the result only when I use the command with the echo statement. For example:

y="HELLO"
echo $y| tr '[:upper:]' '[:lower:]'

The above works and results in 'hello', but I need to assign the result to a variable as below:

y="HELLO"
val=$y| tr '[:upper:]' '[:lower:]'
string=$val world

When assigning the value like above it gives me an empty result.

PS: My Bash version is 3.1.17

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
raga
  • 1,483
  • 2
  • 13
  • 13

7 Answers7

234

If you are using Bash 4, you can use the following approach:

x="HELLO"
echo $x  # HELLO

y=${x,,}
echo $y  # hello

z=${y^^}
echo $z  # HELLO

Use only one , or ^ to make the first letter lowercase or uppercase.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
kev
  • 155,172
  • 47
  • 273
  • 272
  • 2
    Thanks for your immediate response. When i tried the above it says ${y,,}--bad substitution. Any how i tried another approach of y="HI" val = $( tr '[A-Z]' '[a-z]' <<< $y) and this worked for me.Thanks once again – raga Jul 09 '12 at 09:55
  • 10
    Your bash version too low. It doesn't support those features. – kev Jul 09 '12 at 09:58
  • Yes...Am trying to do the same logic in ant build.xml file.Trying to convert a string from uppercase to lowercase.How do I achievce that.Tried scriptdef pattern and others and it dint work.. – raga Jul 09 '12 at 10:15
  • bash string substitution doesn't work on centos 5.9 – nurettin Apr 02 '13 at 12:54
  • 8
    The ,, ^^ substitutions only work on bash 4, not bash 3 so you'd need to upgrade bash or use the tr approach. – Ian Oct 21 '13 at 09:52
  • 2
    If bad substitution message is returned, also check if you accidentally wrote '$' before variable name (${$y,,} instead of ${y,,}), which results in the same error as when bash version is too low (you can check it with 'bash --version'). – BartekM Oct 17 '16 at 12:15
  • 5
    I was confused for a moment because I was doing `bash --version` and getting 5.0.3, but then realized that was brew version of bash (at `/usr/local/bin/bash`). My script had my system bash in the header with `#!/bin/bash` which was version 3 :( – combinatorist Jan 21 '20 at 19:59
  • bash version 4.4.20(1)-release `bad substitution` – yuklia Dec 20 '21 at 09:58
  • version 5.1.12(1)-release in /usr/local/bin/bash (brew) also failing on the CLI with the above error – volvox Jan 04 '22 at 15:35
88

One way to implement your code is

y="HELLO"
val=$(echo "$y" | tr '[:upper:]' '[:lower:]')
string="$val world"

This uses $(...) notation to capture the output of the command in a variable. Note also the quotation marks around the string variable -- you need them there to indicate that $val and world are a single thing to be assigned to string.

If you have Bash 4.0 or higher, a more efficient & elegant way to do it is to use Bash built-in string manipulation:

y="HELLO"
string="${y,,} world"
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rody Oldenhuis
  • 37,726
  • 7
  • 50
  • 96
34

Note that tr can only handle plain ASCII, making any tr-based solution fail when facing international characters.

Same goes for the Bash 4-based ${x,,} solution.

The AWK tool, on the other hand, properly supports even UTF-8 / multibyte input.

y="HELLO"
val=$(echo "$y" | awk '{print tolower($0)}')
string="$val world"

Answer courtesy of liborw.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
DevSolar
  • 67,862
  • 21
  • 134
  • 209
26

Execute in backticks:

 x=`echo "$y" | tr '[:upper:]' '[:lower:]'` 

This assigns the result of the command in backticks to the variable x. (I.e., it's not particular to tr, but it is a common pattern/solution for shell scripting.)

You can use $(..) instead of the backticks. See here for more info.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
  • 5
    Thanks a lot for your answer. the above works..to make it better i tried y="HI" val = $( tr '[A-Z]' '[a-z]' <<< $y) and it worked fine for me..Thank you once again for your suggestion – raga Jul 09 '12 at 09:51
  • 1
    @raga `<<<` - love it!!! much more elegant than `echo` "overkill" ☺︎ – msciwoj Dec 05 '14 at 12:09
  • 1
    Just remember that `\$`, double backslash and backslash backtick will not be treated literally with backticks, but they will inside `$(..)`. That could be good or bad depending on your usecase. http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html Section 3.4.5. – Jeremy Jun 05 '15 at 20:55
10

I'm on Ubuntu 14.04 (Trusty Tahr), with Bash version 4.3.11. However, I still don't have the fun built-in string manipulation ${y,,}

This is what I used in my script to force capitalization:

CAPITALIZED=`echo "${y}" | tr '[a-z]' '[A-Z]'`
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
BoomShadow
  • 912
  • 1
  • 18
  • 31
6

If you define your variable using declare (old: typeset) then you can state the case of the value throughout the variable's use.

declare -u FOO=AbCxxx
echo $FOO

Output:

ABCXXX

Option -l to declare does lowercase:

When the variable is assigned a value, all upper-case characters are converted to lower-case. The upper-case attribute is disabled.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Steven Powell
  • 115
  • 2
  • 7
4

Building on Rody's answer, this worked for me.

y="HELLO"
val=$(echo $y | tr '[:upper:]' '[:lower:]')
string="$val world"

One small modification: if you are using underscore next to the variable, you need to encapsulate the variable name in {}.

string="${val}_world"
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ray Moncada
  • 63
  • 1
  • 3