|

Linux CLI 66 ๐Ÿง Case conversion in shell scripts

โฑ๏ธ Estimated read: 14 min | |

#!/bin/bash
var="Hello World"
uppercase="${var^^}"
lowercase="${var,,}"
echo "$uppercase"
echo "$lowercase"

var1="Hello World"
uppercase1=$(echo "$var" | tr '[:lower:]' '[:upper:]')
lowercase1=$(echo "$var" | tr '[:upper:]' '[:lower:]')
echo "$uppercase1"
echo "$lowercase1"

var2="Hello World"
uppercase2=$(echo "$var" | awk '{print toupper($0)}')
lowercase2=$(echo "$var" | awk '{print tolower($0)}')
echo "$uppercase2"
echo "$lowercase2"

var3="Hello World"
uppercase3=$(echo "$var" | sed 's/[a-z]/\U&/g')
lowercase3=$(echo "$var" | sed 's/[A-Z]/\L&/g')
echo "$uppercase3"
echo "$lowercase3"

declare -l name="Hello World"
echo "$name"

declare -u name="Hello World"
echo "$name"

Converting strings to uppercase or lowercase comes up constantly โ€” normalizing user input, formatting output, comparing values case-insensitively. Bash gives you four different ways to do it, each with different trade-offs in portability, speed, and readability.

Key point: The fastest and cleanest method is bash’s built-in parameter expansion (${var^^} and ${var,,}). The most portable is tr. The most flexible is awk or sed. And declare lets you force a variable’s case on assignment.


a – Case conversion with parameter expansion

Case conversion means converting strings to uppercase or lowercase. It can be performed using several methods, depending on the shell and the context of the script.

Method 1 โ€” Parameter expansion ^^ and ,,:

#!/bin/bash
var="Hello World"
uppercase="${var^^}"
lowercase="${var,,}"
echo "$uppercase"
echo "$lowercase"
[ HELLO WORLD ]
[ hello world ]
  • ${var^^} โ†’ uppercase the whole string
  • ${var,,} โ†’ lowercase the whole string

There are also single-character versions:

FormEffect
${var^}Uppercase first character
${var^^}Uppercase all characters
${var,}Lowercase first character
${var,,}Lowercase all characters
$ var="hello world"
$ echo "${var^}"
[ Hello world ]
$ echo "${var^^}"
[ HELLO WORLD ]

$ var="HELLO WORLD"
$ echo "${var,}"
[ hELLO WORLD ]
$ echo "${var,,}"
[ hello world ]

You can also convert only matching characters:

$ var="hello world"
$ echo "${var^^[hw]}"
[ Hello World ]
$ echo "${var^^[a-z]}"
[ HELLO WORLD ]

${var^^[pattern]} uppercases only characters matching pattern; ${var,,[pattern]} lowercases only those matching.

Pros:

  • Clean and readable
  • Fast and efficient
  • No external commands needed

Cons:

  • Not portable to non-bash shells (like dash, ksh, or zsh without set -o extglob)
  • Not POSIX-compliant
  • Requires bash 4.0+ for ^^ and ,, (4.2+ for the pattern variants)

Method 2 โ€” tr:

#!/bin/bash
var1="Hello World"
uppercase1=$(echo "$var" | tr '[:lower:]' '[:upper:]')
lowercase1=$(echo "$var" | tr '[:upper:]' '[:lower:]')
echo "$uppercase1"
echo "$lowercase1"
[ HELLO WORLD ]
[ hello world ]

tr translates characters. [:lower:] โ†’ [:upper:] maps each lowercase letter to its uppercase counterpart.

You can also use explicit ranges:

$ echo "hello" | tr 'a-z' 'A-Z'
[ HELLO ]
$ echo "HELLO" | tr 'A-Z' 'a-z'
[ hello ]

Pros:

  • Works in any shell that supports tr
  • Portable and widely available on Unix systems
  • Predictable behavior

Cons:

  • Requires invoking an external command
  • Less efficient for large-scale operations
  • Spawns a subprocess for every call

Parameter expansion vs tr:

Aspect${var^^} / ${var,,}tr
SpeedInstant (built-in)Spawns a process
PortabilityBash 4+Any shell
ReadabilityVery cleanSlightly noisy
Pattern controlYes ([a-z])Via character ranges
Works onVariable valuesStreams / stdin

b – Case conversion with awk and sed

Method 3 โ€” awk:

#!/bin/bash
var2="Hello World"
uppercase2=$(echo "$var" | awk '{print toupper($0)}')
lowercase2=$(echo "$var" | awk '{print tolower($0)}')
echo "$uppercase2"
echo "$lowercase2"
[ HELLO WORLD ]
[ hello world ]

awk‘s toupper() and tolower() functions operate on $0 (the whole line) or on any string expression.

Pros:

  • Can handle more complex string manipulation
  • Portable across shells
  • Useful when you’re already using awk for other processing

Cons:

  • Slightly slower than tr or parameter expansion
  • Requires the external awk command
  • Overkill for simple case conversion

Method 4 โ€” sed:

#!/bin/bash
var3="Hello World"
uppercase3=$(echo "$var" | sed 's/[a-z]/\U&/g')
lowercase3=$(echo "$var" | sed 's/[A-Z]/\L&/g')
echo "$uppercase3"
echo "$lowercase3"
[ HELLO WORLD ]
[ hello world ]

sed‘s \U and \L escape sequences change the case of the replacement. Combined with & (the whole match), they convert each matched character.

  • s/[a-z]/\U&/g โ†’ for each lowercase letter, replace it with its uppercase form
  • s/[A-Z]/\L&/g โ†’ for each uppercase letter, replace it with its lowercase form

Pros:

  • Highly flexible for advanced text transformations
  • Can combine case conversion with other edits in one pass

Cons:

  • More complex and harder to read
  • Slower and less efficient
  • GNU-specific โ€” \U and \L may not work in BSD/macOS sed

Comparison of all four methods:

MethodSpeedPortabilityReadabilityBest for
${var^^} / ${var,,}FastestBash 4+HighestBash scripts
trFastPOSIXHighPortable scripts
awkMediumPOSIXMediumComplex processing
sedSlowGNU mostlyLowCombined edits

Recommendations:

  • Use ${var^^} and ${var,,} if your script is bash-specific and you want cleaner, faster code
  • Use tr if you need POSIX compliance or maximum portability
  • Use awk if you need complex transformations or additional string manipulation
  • Use sed if you’re already using it for other edits and want to combine

A note on locale:

Case conversion is locale-aware. Under a UTF-8 locale, tr '[:lower:]' '[:upper:]' and ${var^^} handle accented characters (รฉ โ†’ ร‰). Under LC_ALL=C, they only handle ASCII. Set the locale explicitly if behavior matters:

$ LC_ALL=C tr '[:lower:]' '[:upper:]' <<< "cafรฉ"
[ CAFรฉ ]
$ LC_ALL=en_US.UTF-8 tr '[:lower:]' '[:upper:]' <<< "cafรฉ"
[ CAFร‰ ]

c – Case conversion with declare

The declare command is primarily used to declare variables and assign attributes to them โ€” such as making them read-only, integer-typed, or modifying their case automatically.

While declare is not directly used for case conversion, it supports two options that automatically enforce case on the values of variables:

  • declare -l var โ†’ Forces the variable var to always store its value in lowercase
  • declare -u var โ†’ Forces the variable var to always store its value in uppercase

Example:

declare -l name="Hello World"
echo "$name"
[ hello world ]

declare -u name="Hello World"
echo "$name"
[ HELLO WORLD ]

Every assignment to a declare -l variable is automatically lowercased. Every assignment to a declare -u variable is automatically uppercased.

$ declare -l name
$ name="HELLO World"
$ echo "$name"
[ hello world ]

$ name="ANOTHER Assignment"
$ echo "$name"
[ another assignment ]

The variable stays lowercase no matter what you assign.

Useful for normalization:

#!/bin/bash
declare -l answer
read -p "Continue? (y/n): " answer

case "$answer" in
    y|yes) echo "Continuing" ;;
    n|no)  echo "Cancelled" ;;
    *)     echo "Please answer yes or no" ;;
esac

The user’s input is normalized to lowercase automatically, so Y, Yes, and YES all match.

Limitations:

  • Not POSIX-compliant โ€” specific to bash
  • No string-level case conversion โ€” it works on assignment, not on arbitrary expressions
  • No mixed-case enforcement โ€” it’s all-or-nothing
  • Only works on variable assignment โ€” not on command outputs or piped data
  • Resets on function scope โ€” a declare -l inside a function applies only there

The declare case attributes:

CommandEffect
declare -l varVariable is always lowercase
declare -u varVariable is always uppercase
declare -l var="HELLO"Declare and assign (value lowercased)
declare -u var="hello"Declare and assign (value uppercased)

Listing declared variables:

$ declare -l name
$ declare -p name
[ declare -l name="hello world" ]

$ declare -u code
$ code="abc"
$ declare -p code
[ declare -u code="ABC" ]

declare -l vs ${var,,}:

Aspectdeclare -l${var,,}
When it appliesOn assignmentWhen you ask
PersistenceAlwaysOne-time
Syntaxdeclare -l x${x,,}
Use forNormalized storageOne-off conversion

If a variable should always be lowercase โ€” user input, config keys, hostnames โ€” use declare -l. If you need to lowercase something once for comparison, use ${var,,}.


Complete Example Session

# ============================================
# PART 1: PARAMETER EXPANSION
# ============================================

$ var="Hello World"
$ echo "${var^^}"
[ HELLO WORLD ]
$ echo "${var,,}"
[ hello world ]

$ echo "${var^}"
[ Hello World ]
$ echo "${var,}"
[ hello World ]

# ============================================
# PART 2: PATTERN-SPECIFIC CONVERSION
# ============================================

$ var="hello world"
$ echo "${var^^[hw]}"
[ Hello World ]
$ echo "${var^^[a-z]}"
[ HELLO WORLD ]

# ============================================
# PART 3: TR
# ============================================

$ var1="Hello World"
$ echo "$var1" | tr '[:lower:]' '[:upper:]'
[ HELLO WORLD ]
$ echo "$var1" | tr '[:upper:]' '[:lower:]'
[ hello world ]

$ echo "hello" | tr 'a-z' 'A-Z'
[ HELLO ]
$ echo "HELLO" | tr 'A-Z' 'a-z'
[ hello ]

# ============================================
# PART 4: AWK
# ============================================

$ var2="Hello World"
$ echo "$var2" | awk '{print toupper($0)}'
[ HELLO WORLD ]
$ echo "$var2" | awk '{print tolower($0)}'
[ hello world ]

# ============================================
# PART 5: SED
# ============================================

$ var3="Hello World"
$ echo "$var3" | sed 's/[a-z]/\U&/g'
[ HELLO WORLD ]
$ echo "$var3" | sed 's/[A-Z]/\L&/g'
[ hello world ]

# ============================================
# PART 6: DECLARE
# ============================================

$ declare -l name="Hello World"
$ echo "$name"
[ hello world ]

$ declare -u code="hello world"
$ echo "$code"
[ HELLO WORLD ]

$ declare -l answer
$ answer="YES"
$ echo "$answer"
[ yes ]

# ============================================
# PART 7: COMPARE โ€” SAME RESULT
# ============================================

$ var="Hello World"

$ echo "${var^^}"
[ HELLO WORLD ]
$ echo "$var" | tr '[:lower:]' '[:upper:]'
[ HELLO WORLD ]
$ echo "$var" | awk '{print toupper($0)}'
[ HELLO WORLD ]
$ echo "$var" | sed 's/[a-z]/\U&/g'
[ HELLO WORLD ]

# ============================================
# PART 8: LOCALE MATTERS
# ============================================

$ LC_ALL=C tr '[:lower:]' '[:upper:]' <<< "cafรฉ"
[ CAFรฉ ]
$ LC_ALL=en_US.UTF-8 tr '[:lower:]' '[:upper:]' <<< "cafรฉ"
[ CAFร‰ ]

# ============================================
# PART 9: NORMALIZE USER INPUT
# ============================================

$ declare -l answer
$ read -p "Continue? (y/n): " answer
Continue? (y/n): Y
$ echo "$answer"
[ y ]

# ============================================
# PART 10: CASE-INSENSITIVE COMPARISON
# ============================================

$ name="ALICE"
$ expected="alice"

# โŒ Case-sensitive
$ [ "$name" = "$expected" ] && echo "match" || echo "no match"
[ no match ]

# โœ… Lowercase both sides
$ [ "${name,,}" = "${expected,,}" ] && echo "match" || echo "no match"
[ match ]

# ============================================
# PART 11: NORMALIZE FILE EXTENSIONS
# ============================================

$ for f in *.TXT *.Txt *.txt; do
>     [ -e "$f" ] || continue
>     echo "${f,,}"
> done
[ file1.txt ]
[ file2.txt ]
[ file3.txt ]

# ============================================
# PART 12: FULL SCRIPT
# ============================================

$ cat > case.sh << 'EOF'
#!/bin/bash
var="Hello World"
uppercase="${var^^}"
lowercase="${var,,}"
echo "$uppercase"
echo "$lowercase"

var1="Hello World"
uppercase1=$(echo "$var" | tr '[:lower:]' '[:upper:]')
lowercase1=$(echo "$var" | tr '[:upper:]' '[:lower:]')
echo "$uppercase1"
echo "$lowercase1"

var2="Hello World"
uppercase2=$(echo "$var" | awk '{print toupper($0)}')
lowercase2=$(echo "$var" | awk '{print tolower($0)}')
echo "$uppercase2"
echo "$lowercase2"

var3="Hello World"
uppercase3=$(echo "$var" | sed 's/[a-z]/\U&/g')
lowercase3=$(echo "$var" | sed 's/[A-Z]/\L&/g')
echo "$uppercase3"
echo "$lowercase3"

declare -l name="Hello World"
echo "$name"

declare -u name="Hello World"
echo "$name"
EOF
$ chmod +x case.sh
$ ./case.sh
[ HELLO WORLD ]
[ hello world ]
[ HELLO WORLD ]
[ hello world ]
[ HELLO WORLD ]
[ hello world ]
[ HELLO WORLD ]
[ hello world ]
[ hello world ]
[ HELLO WORLD ]

Quick Reference

Parameter Expansion (bash 4+)

FormEffect
${var^}Uppercase first char
${var^^}Uppercase all
${var,}Lowercase first char
${var,,}Lowercase all
${var^^[pattern]}Uppercase matching
${var,,[pattern]}Lowercase matching

tr

CommandEffect
tr '[:lower:]' '[:upper:]'Uppercase
tr '[:upper:]' '[:lower:]'Lowercase
tr 'a-z' 'A-Z'Uppercase
tr 'A-Z' 'a-z'Lowercase

awk

CommandEffect
awk '{print toupper($0)}'Uppercase
awk '{print tolower($0)}'Lowercase

sed (GNU)

CommandEffect
sed 's/[a-z]/\U&/g'Uppercase
sed 's/[A-Z]/\L&/g'Lowercase

declare

CommandEffect
declare -l varForce lowercase
declare -u varForce uppercase
declare -l var="HELLO"Declare + assign, lowercased
declare -u var="hello"Declare + assign, uppercased
declare -p varShow declaration

Method Comparison

MethodSpeedPortabilityBash 4+ only
${var^^} / ${var,,}FastestโŒ Bash onlyโœ…
trFastโœ… POSIXโŒ
awkMediumโœ… POSIXโŒ
sedSlowGNU mostlyโŒ
declare -l/-uFastestโŒ Bash onlyโœ…

Locale

SettingEffect
LC_ALL=CASCII only
LC_ALL=en_US.UTF-8Unicode-aware

Best Practices

โœ… Do This:

# Use parameter expansion in bash scripts
uppercase="${var^^}"                   # โœ…
lowercase="${var,,}"                   # โœ…

# Use tr for portability
uppercase=$(echo "$var" | tr '[:lower:]' '[:upper:]')  # โœ…

# Normalize user input
declare -l answer                      # โœ…

# Lowercase both sides for comparison
[ "${a,,}" = "${b,,}" ]                # โœ…

# Set locale for Unicode
LC_ALL=en_US.UTF-8 tr '[:lower:]' '[:upper:]'  # โœ…

# Use case-insensitive comparison
shopt -s nocasematch
[[ $a == "$b" ]]                       # โœ…

โŒ Don’t Do This:

# Don't assume ^^ works in sh
#!/bin/sh
echo "${var^^}"                        # โŒ not POSIX

# Don't forget the locale for accents
echo "cafรฉ" | tr '[:lower:]' '[:upper:]'  # โš ๏ธ  may not uppercase รฉ

# Don't mix methods unnecessarily
uppercase=$(echo "$var" | tr ... | awk ... | sed ...)  # โŒ overkill

# Don't use sed for simple case conversion
echo "$var" | sed 's/[a-z]/\U&/g'      # โš ๏ธ  slower than ${var^^}

# Don't forget declare is bash-only
declare -l x                           # โŒ not in sh

# Don't ignore mixed-case patterns
${var^^[a-z]}                          # โœ… converts only letters

Common Pitfalls

PitfallProblemSolution
^^ in shNot POSIXUse tr
Old bash^^ not supportedBash 4.0+ required
LocaleAccents mishandledSet LC_ALL
sed \U on macOSBSD sed differsUse tr or awk
Extra subprocessSlow loopsUse ${var^^}
declare -l in shNot supportedUse ${var,,}
Comparing mixed caseFailsLowercase both sides

Real-World Examples

1. Parameter Expansion Uppercase

#!/bin/bash
var="Hello World"
echo "${var^^}"
[ HELLO WORLD ]

2. Parameter Expansion Lowercase

#!/bin/bash
var="Hello World"
echo "${var,,}"
[ hello world ]

3. First Character Only

#!/bin/bash
var="hello world"
echo "${var^}"
[ Hello world ]

4. tr Uppercase

#!/bin/bash
var1="Hello World"
echo "$var1" | tr '[:lower:]' '[:upper:]'
[ HELLO WORLD ]

5. tr Lowercase

#!/bin/bash
var1="Hello World"
echo "$var1" | tr '[:upper:]' '[:lower:]'
[ hello world ]

6. awk Uppercase

#!/bin/bash
var2="Hello World"
echo "$var2" | awk '{print toupper($0)}'
[ HELLO WORLD ]

7. awk Lowercase

#!/bin/bash
var2="Hello World"
echo "$var2" | awk '{print tolower($0)}'
[ hello world ]

8. sed Uppercase

#!/bin/bash
var3="Hello World"
echo "$var3" | sed 's/[a-z]/\U&/g'
[ HELLO WORLD ]

9. sed Lowercase

#!/bin/bash
var3="Hello World"
echo "$var3" | sed 's/[A-Z]/\L&/g'
[ hello world ]

10. declare Lowercase

#!/bin/bash
declare -l name="Hello World"
echo "$name"
[ hello world ]

11. declare Uppercase

#!/bin/bash
declare -u name="Hello World"
echo "$name"
[ HELLO WORLD ]

12. Case-Insensitive Comparison

#!/bin/bash
a="ALICE"
b="alice"
if [ "${a,,}" = "${b,,}" ]; then
    echo "Match"
fi
[ Match ]

13. Normalize User Input

#!/bin/bash
declare -l answer
read -p "Continue? (y/n): " answer
case "$answer" in
    y|yes) echo "Continuing" ;;
    n|no)  echo "Cancelled" ;;
    *)     echo "Invalid" ;;
esac

14. Normalize File Extensions

#!/bin/bash
for f in *; do
    ext="${f##*.}"
    if [ "${ext,,}" = "txt" ]; then
        echo "Text file: $f"
    fi
done

15. Uppercase Config Keys

#!/bin/bash
while IFS='=' read -r key value; do
    echo "${key^^}=$value"
done < config.ini

16. Check Root Username

#!/bin/bash
if [ "${USER,,}" = "root" ]; then
    echo "Running as root"
fi

17. Normalize Hostname

#!/bin/bash
host="${1,,}"
echo "Connecting to $host..."

18. Convert Filename Case

#!/bin/bash
for f in *.txt; do
    echo "${f^^}"
done

19. Batch Rename to Lowercase

#!/bin/bash
for f in *; do
    new="${f,,}"
    [ "$f" != "$new" ] && mv "$f" "$new"
done

20. Full Script

#!/bin/bash
var="Hello World"
uppercase="${var^^}"
lowercase="${var,,}"
echo "$uppercase"
echo "$lowercase"

var1="Hello World"
uppercase1=$(echo "$var" | tr '[:lower:]' '[:upper:]')
lowercase1=$(echo "$var" | tr '[:upper:]' '[:lower:]')
echo "$uppercase1"
echo "$lowercase1"

var2="Hello World"
uppercase2=$(echo "$var" | awk '{print toupper($0)}')
lowercase2=$(echo "$var" | awk '{print tolower($0)}')
echo "$uppercase2"
echo "$lowercase2"

var3="Hello World"
uppercase3=$(echo "$var" | sed 's/[a-z]/\U&/g')
lowercase3=$(echo "$var" | sed 's/[A-Z]/\L&/g')
echo "$uppercase3"
echo "$lowercase3"

declare -l name="Hello World"
echo "$name"

declare -u name="Hello World"
echo "$name"

Visual: Four Ways, Same Result

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Input: "Hello World"                        โ”‚
โ”‚                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  ${var^^}                              โ”‚  โ”‚
โ”‚  โ”‚  โ†’ HELLO WORLD          (fastest)      โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  tr '[:lower:]' '[:upper:]'            โ”‚  โ”‚
โ”‚  โ”‚  โ†’ HELLO WORLD          (portable)     โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  awk '{print toupper($0)}'             โ”‚  โ”‚
โ”‚  โ”‚  โ†’ HELLO WORLD          (flexible)     โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  sed 's/[a-z]/\U&/g'                   โ”‚  โ”‚
โ”‚  โ”‚  โ†’ HELLO WORLD          (combined)     โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Visual: declare -l vs ${var,,}

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚           declare -l (persistent)            โ”‚
โ”‚                                              โ”‚
โ”‚  declare -l name                             โ”‚
โ”‚  name="HELLO World"                          โ”‚
โ”‚  echo "$name"  โ†’ hello world                 โ”‚
โ”‚  name="ANOTHER"                              โ”‚
โ”‚  echo "$name"  โ†’ another                     โ”‚
โ”‚                                              โ”‚
โ”‚  Always lowercase, on every assignment.      โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚           ${var,,} (one-time)                โ”‚
โ”‚                                              โ”‚
โ”‚  name="HELLO World"                          โ”‚
โ”‚  echo "${name,,}"  โ†’ hello world             โ”‚
โ”‚  echo "$name"      โ†’ HELLO World             โ”‚
โ”‚                                              โ”‚
โ”‚  Lowercases only when you ask.               โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

MethodSyntaxSpeedPortability
Parameter expansion${var^^} / ${var,,}FastestBash 4+
trtr '[:lower:]' '[:upper:]'FastPOSIX
awkawk '{print toupper($0)}'MediumPOSIX
sedsed 's/[a-z]/\U&/g'SlowGNU
declaredeclare -l/-u varFastestBash only

Key takeaways:

  • ${var^^} and ${var,,} are the fastest, cleanest way โ€” but bash 4+ only
  • tr is the most portable โ€” works everywhere, POSIX
  • awk is flexible โ€” good when you’re already using it
  • sed with \U / \L is powerful but slower and GNU-specific
  • declare -l and declare -u force a variable’s case on every assignment
  • Use ${var^} and ${var,} for first-character-only conversion
  • Use ${var^^[pattern]} to convert only matching characters
  • Case conversion is locale-aware โ€” set LC_ALL for Unicode
  • For case-insensitive comparison, lowercase both sides: [ "${a,,}" = "${b,,}" ]
  • For normalizing input, declare -l is elegant
  • In bash scripts, default to ${var^^} โ€” it’s the idiomatic, fastest choice
  • In portable scripts, use tr

Remember: Case conversion is a common task with multiple solutions. In modern bash, reach for ${var^^} and ${var,,} โ€” they’re built-in, fast, and clean. When portability matters, use tr. When you want a variable to always be normalized, use declare -l or declare -u. And remember that case conversion is locale-sensitive โ€” set LC_ALL when Unicode matters. Master these four methods and you’ll pick the right one every time.

Was this helpful?


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!