126

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

Tried

#!/bin/bash
             ## 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?

151

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 '12 at 12:46
  • 1
    @manatwork That is not clearly stated in the initial question. The bad substitution error message is the same as you would get with older bash versions. – Bernhard Oct 16 '12 at 12:48
  • 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 '12 at 12:51
  • 21
    @mtk That should be tr '[a-z]' '[A-Z]'. – l0b0 Oct 17 '12 at 9:43
  • 2
    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. – Heath Borders Jan 26 '16 at 23:19
82
echo "lowercase" | tr a-z A-Z

Output:

LOWERCASE
24

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/'
ABCåäö
$ echo "$str"|LC_ALL=sv_SE tr '[:lower:]' '[:upper:]'
ABCåäö
$ echo "$str"|awk '{print toupper($0)}'
ABCÅÄÖ
$ echo ${str^^} # Bash 4.0 and later
ABCÅÄÖ
$ STR="ABCÅÄÖ"
$ echo ${STR,,}
abcåäö
  • 1
    FWIW, tr '[:lower:]' '[:upper:]' is working now for your example on OS X at least (also with LC_ALL=sv_SE) – Ethan Mar 31 '17 at 21:57
1

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:

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

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).

0

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())"
I WILL BE 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$_"'
I WILL BE UPPER

Not the answer you're looking for? Browse other questions tagged or ask your own question.