swapcase with the tr command

Published: 2022-04-01

Categories:
command line


Want to easily swap the case of some string on the *nix command line? The tr command can do that!

You may already know the tr command can switch lowercase to uppercase

$ echo "HI there" | tr '[:lower:]' '[:upper:]'
HI THERE

Or uppercase to lowercase

$ echo "HI there" | tr '[:lower:]' '[:upper:]' | tr '[:upper:]' '[:lower:]'
hi there

But we can take it further and tell tr not only switch all lowercase to uppercase but all uppercase to lowercase in one transform!

$ echo "HI there" | tr '[:lower:][:upper:]' '[:upper:][:lower:]'
hi THERE

And because we’re using character classes and not simply a-zA-Z that means unicode letters work as well.

$ echo "CAfé" | tr "[:lower:][:upper:]" "[:upper:][:lower:]"
caFÉ

This works because the arguments to tr are a paired list of transforms. Each character in string1 (the first argument) will be replaced with the corresponding index of the character from string2 (the second argument)

$ echo crab | tr abc ABC
CrAB

The above command has abc for the first string and ABC for the second. That means tr will pair them up like so

a => A
b => B
c => C

Having tr perform a swapcase means making those strings include both uppercase and lowercase characters. If we were to pick randomly from the translation pairs it could look like this.

P => p
k => K
X => x
x => X
W => w
M => m
F => f

Why do this? Well for me I wanted a list of lowercase letters, uppercase letters, and numbers. printable-ascii can easily provide me with that list but I wanted to go from lowercase to uppercase to numbers. But ASCII order has uppercase first.

$ printable-ascii --letters --digits --compact
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789

I could tell printable-ascii more explicitly how to order the output by manually defining the ranges in the order I want

$ printable-ascii --range a-z --range A-Z --digits --compact
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789

But the tr command can easily do that work for me. And since I’m dealing explicitly with ASCII I can simply use a-zA-Z

$ printable-ascii --letters --digits --compact | tr A-Za-z a-zA-Z
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789