I searched SO and found that to uppercase a string following would work

str="Some string"
echo ${str^^}

But I tried to do a similar thing on a command-line argument, which gave me the following error


             ## Output
echo ${1^^}  ## line 3: ${1^^}: bad substitution
echo {$1^^}  ## No error, but output was still smaller case i.e. no effect

How could we do this?


6 Answers 6


The syntax str^^ which you are trying is available from Bash 4.0 and above. Perhaps yours is an older version (or you ran the script with sh explicitly):

Try this:

str="Some string"
printf '%s\n' "$str" | awk '{ print toupper($0) }'
  • 1
    From mtk's words I understood that case modification actually works for him with variables.
    – manatwork
    Oct 16, 2012 at 12:46
  • 4
    You are correct. I checked the version, its 3.2.25. Your solution works and also I tried tr '[a-z]' [[A-Z]'.
    – mtk
    Oct 16, 2012 at 12:51
  • 27
    @mtk That should be tr '[a-z]' '[A-Z]'.
    – l0b0
    Oct 17, 2012 at 9:43
  • 3
    I'm running GNU bash, version 4.3.42(1)-release (x86_64-apple-darwin14.5.0), and I get the same error as OP, so I don't think this is available on any bash 4.0 and above as you say. Jan 26, 2016 at 23:19
  • 2
    @ZoeyHewll – printf doesn't accept options, so it's much more reliable and predictable given something like str="-n" (try echo "-n" or echo -- "-n" vs printf "%s\n" "-n").
    – Adam Katz
    Oct 12, 2021 at 20:12
echo "lowercase" | tr a-z A-Z


  • 5
    I think POSIX does not require the / as in tr /a-z/ /A-Z/ before my edit: this just works because it replaces / by / but is useless: pubs.opengroup.org/onlinepubs/9699919799/utilities/tr.html There also exists the more obscure and less useful tr '[:lower:]' '[:upper:]'. May 9, 2018 at 16:22
  • Correct. tr is very different, but it works.
    – Doug
    Sep 6, 2018 at 16:52
  • 1
    umlauts are not working with this.
    – Ievgen
    Jan 31, 2019 at 15:04
  • 1
    As @CiroSantilli冠状病毒审查六四事件法轮功 mentioned, you can use `tr '[:lower:]' '[:upper:]' to handle non-a-z characters. (Indeed, the "less useful" comment seems to be the opposite. using lower/upper covers a wider range of characters.)
    – jasonkarns
    Apr 8, 2020 at 13:30

Be careful with tr unless A-Z is all you use. For other locales even '[:lower:]' '[:upper:]' fails, only awk's toupper and bash (v4+) works:

$ str="abcåäö"

$ echo "$str" | tr '/a-z/' '/A-Z/'

$ echo "$str" | LC_ALL=sv_SE tr '[:lower:]' '[:upper:]'

$ echo "$str" | awk '{print toupper($0)}'

$ echo ${str^^} # Bash 4.0 and later

$ echo ${STR,,}
  • 2
    FWIW, tr '[:lower:]' '[:upper:]' is working now for your example on OS X at least (also with LC_ALL=sv_SE)
    – Ethan
    Mar 31, 2017 at 21:57
  • That's a limitation (and non-compliance) of GNU tr and a few others. tr '[:lower:]' '[:upper:]' is meant to work on any letter that have an uppercase variant in the locale, not just A-Z (whatever A-Z means, does it include É, Æ?). You have the same problem with some implementations of awk with toupper(), such as mawk, the default awk on Ubuntu. Aug 18, 2023 at 7:42

Alternatively, you could switch to ksh or zsh which have had case conversion support for decades (long before bash's ${var^^} added in 4.0), though with a different syntax:

#! /bin/ksh -
typeset -u upper="$1"
printf '%s\n' "$upper"

(also works with zsh; note that in pdksh/mksh, that only works for ASCII letters).

With zsh, you can also use the U parameter expansion flag or the csh style¹ u modifier:

#! /bin/zsh -
printf '%s\n' "${(U)1}" "$1:u"

POSIXLY, you can use:

awk -- 'BEGIN{print toupper(ARGV[1])}' "$1"

There's also:

printf '%s\n' "$1" | tr '[:lower:]' '[:upper:]'

But in a few implementations, including GNU tr, that only works for single-byte characters (so in UTF-8 locales, only on ASCII letters, not accented letters of the Latin alphabet, not ligatures, not letters from other alphabets that also have a concept of case such as the Greek or Cyrillic alphabets).

In practice, none of those work for characters that don't have a single-character uppercase version such as whose uppercase is FFI or the German ß. perl's uc (upper case) would work for those:

$ perl -CSA -le 'print uc for @ARGV' -- groß suffix

Here with -CLSA to specify that the Stdio streams and Arguments are meant to be encoded in UTF-8 as long as UTF-8 is the charmap used in the Locale.

¹ though that modifier specifically is originally from zsh, already there in 1.0 from 1990, copied by tcsh later in 1992 for 6.01.03.


Try quoting the string:

echo "${str^^}"

If someone is still getting error trying ${str^^}, you can try python -c or perl It is likely because bash version is lower than 4.

But, so far bash 4 or over is working swiftly with the existing solution.

L2U="I will be upper"

Using python -c in bash

python -c "print('$L2U'.upper())"

Similarly it also can be used to capitalise with:

service="bootup.sh on home"
python -c "print('$service'.capitalize())"
Bootup.sh on home

Using perl

echo $L2U | perl -ne 'print "\U$_"'
  • 1
    While using python or perl here is a good idea, the fact that you embed the expansion of the shell variable in the code passed to those interpreters (in the python ones) make it a code injection vulnerability and is very bad practice. It may explain the downvotes you got. You also forgot the quotes around $L2U in the last one, and remember echo can't be used to output arbitrary data. Aug 18, 2023 at 7:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .