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:
\nline break,\ttab,\rcarriage return,\\backslash,\NNNoctal (for example\011is 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'andTwo strings must be given when translating.: add SET2, or use-dto delete.tr: extra operand 'b'andOnly one string may be given when deleting without squeezing repeats.:tr -dtakes 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.