Updated: 18 October 2026 · Applies to: GNU coreutils 9.7 on Debian 13 and 9.5 on AlmaLinux 10.2, uutils coreutils 0.10.0 on Ubuntu 26.04, tested (identical output)

The tr (translate) command replaces, deletes or squeezes single characters. It reads only standard input and writes to standard output, so you pipe text into it or redirect a file: tr 'a-z' 'A-Z' < file.txt prints the file in capitals. It works on characters, not words; to replace words or strings, use sed.

tr [OPTION] SET1 [SET2]
tr 'abc' 'xyz'     # a becomes x, b becomes y, c becomes z
tr -d 'SET1'       # delete these characters
tr -s 'SET1'       # squeeze repeated characters into one
tr -c ...          # use every character that is NOT in SET1
tr -t SET1 SET2    # cut SET1 to the length of SET2

All examples below were run on the three systems listed above; the output is a lab example.

1. Convert lowercase to uppercase (and back)

$ cat linux.txt
linux is my life
linux has changed my life
linux is best and everything to me
$ tr 'a-z' 'A-Z' < linux.txt
LINUX IS MY LIFE
LINUX HAS CHANGED MY LIFE
LINUX IS BEST AND EVERYTHING TO ME
$ echo 'Hello WORLD' | tr 'A-Z' 'a-z'
hello world

tr '[:lower:]' '[:upper:]' gives the same result. Always quote the sets. Unquoted brackets are file name patterns for the shell. With a file called o in the folder, the shell turned [a-z] into o:

$ touch o
$ echo hello | tr [a-z] [A-Z]
hell[

2. Save the result to a file

tr 'a-z' 'A-Z' < linux.txt > upper.txt

tr does not take a file name. tr 'a-z' 'A-Z' linux.txt fails with tr: extra operand 'linux.txt'. Never redirect back into the same file: tr 'a-z' 'A-Z' < same.txt > same.txt left same.txt with 0 bytes, because the shell empties the output file before tr reads it. Write to a new file, then rename it with mv.

3. Delete characters with -d

$ echo 'www. example. com' | tr -d ' '
www.example.com
$ echo 'My UID is 1000' | tr -d 'a-zA-Z'
   1000

A common server use is removing Windows line endings (\r) from a file uploaded from a PC. cat -A shows them as ^M:

$ cat -A win.conf
server_name example.com;^M$
root /var/www/html;^M$
$ tr -d '\r' < win.conf > unix.conf; cat -A unix.conf
server_name example.com;$
root /var/www/html;$

4. Keep only some characters with -c

-c means "every character not in SET1". Together with -d it keeps only what you list. Add \n to keep the line break:

$ echo 'My UID is 1000' | tr -cd '[:digit:]\n'
1000
$ echo 'phone: +91 98470 12345' | tr -cd '0-9\n'
919847012345

The same idea makes a random 16-character password from the kernel's random source (your result will differ):

$ tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 16; echo
1nVpL2yaGU9qUKkr

5. Squeeze repeated characters with -s

$ echo 'www.example.....com' | tr -s '.'
www.example.com
$ echo 'too    many   spaces' | tr -s ' '
too many spaces
$ printf 'line1\n\n\nline2\n' | tr -s '\n'
line1
line2

The last command removes empty lines.

6. Split words onto lines, or join lines

$ echo 'My UID is 1000' | tr ' ' '\n'
My
UID
is
1000
$ echo 'one  two   three' | tr -s ' ' '\n'
one
two
three
$ echo '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin' | tr ':' '\n'
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin

With -s and two sets, tr translates first and then squeezes, so several spaces give one line break. The last example splits a PATH style list. To join lines:

$ printf 'web1\nweb2\nweb3\n' | tr '\n' ','; echo
web1,web2,web3,
$ printf 'web1\nweb2\nweb3\n' | paste -sd, -
web1,web2,web3

tr also changes the last line break, which leaves a comma at the end; paste -sd, - does not.

7. Replace characters with other characters

$ printf 'name\tvalue\tunit\n' | tr '\t' ','
name,value,unit
$ echo 'Hello World 2026!' | tr -c '[:alnum:]\n' '_'
Hello_World_2026_
$ echo 'Hello, World! (2026)' | tr -d '[:punct:]'
Hello World 2026
$ echo 'Hello World' | tr 'A-Za-z' 'N-ZA-Mn-za-m'
Uryyb Jbeyq

The first line turns tab-separated text into comma-separated text, the second makes a string safe for a file name, the third removes punctuation, and the last is ROT13: run the same command again to decode it.

When SET2 is shorter than SET1, tr repeats the last character of SET2. Add -t to cut SET1 to the length of SET2 instead:

$ echo 'abcd' | tr 'abcd' 'xy'
xyyy
$ echo 'abcd' | tr -t 'abcd' 'xy'
xycd

Sets you can use

  • Ranges: a-z, A-Z, 0-9.
  • Classes: [:alnum:], [:alpha:], [:digit:], [:lower:], [:upper:], [:space:] (all whitespace including line breaks), [:blank:] (spaces and tabs), [:punct:], [:xdigit:], [:cntrl:], [:print:], [:graph:].
  • Escapes: \n line break, \t tab, \r carriage return, \\ backslash, \NNN octal (for example \011 is a tab).

When translating, the only classes allowed in SET2 are [:lower:] and [:upper:], used as a pair for case conversion. This list comes from tr --help of GNU coreutils 9.7.

Accented letters: tr works byte by byte

Both GNU tr and the uutils tr on Ubuntu 26.04 treat text as bytes, even in a UTF-8 locale. A letter such as é is two bytes, so the results go wrong:

$ echo 'café' | tr 'é' 'e'
cafee
$ echo 'café' | tr '[:lower:]' '[:upper:]'
CAFé
$ echo 'naïve café' | tr -d 'é'
na�ve caf

The last command also damaged the ï, which shares a byte with é. For text with accents, use sed, which replaced both letters correctly in our test: sed 's/é/e/g; s/ï/i/g' printed cafe naive.

GNU tr and uutils tr (Ubuntu 26.04)

On Ubuntu 26.04, tr is the Rust rewrite from the rust-coreutils package:

$ tr --version | head -1
tr (uutils coreutils) 0.10.0
$ readlink -f $(command -v tr)
/usr/lib/cargo/bin/coreutils/tr

Every example in this article gave the same output as GNU tr 9.7 (Debian 13) and 9.5 (AlmaLinux 10.2), including the byte-by-byte behaviour above. The only difference we found was the wording of one error message:

$ echo x | tr '[:upper:]' '[:digit:]'
tr: when translating, the only character classes that may appear in set2 are 'upper' and 'lower'

GNU tr says string2 instead of set2, so scripts that match tr's error text may need a change. The uutils tr --help is also shorter and does not list the classes and escapes. The GNU version is still installed as gnutr (gnutr --version printed tr (GNU coreutils) 9.7).

Common errors

  • tr: missing operand after 'a-z' and Two strings must be given when translating.: add SET2, or use -d to delete.
  • tr: extra operand 'b' and Only one string may be given when deleting without squeezing repeats.: tr -d takes one set.
  • tr: range-endpoints of 'z-a' are in reverse collating sequence order: write ranges from low to high (a-z).
  • tr: extra operand 'file.txt': tr reads standard input only; use < file.txt.

tr is often combined with other text tools: see Linux Text Processing Commands: grep, sort, uniq, wc, cut, tr and diff, How to Count Word Occurrences in a Text File and The echo Command in Linux.

Official documentation: GNU coreutils: tr.

Related services

KVM VPS hosting

NVMe SSD and full root access, with Free Basic Managed Support.

Unmanaged dedicated servers

full root access and free IPMI KVM, with Free Basic Managed Support.

Managed dedicated servers

our engineers look after the server for you, from $135 a month.

Was this answer helpful?

Still stuck? Open a ticket