Linux tr Command
last modified October 23, 2026
The tr (translate) command in Linux replaces, deletes, or
squeezes characters. It reads standard input, transforms it character by
character according to one or two sets of characters, and writes the result
to standard output.
The syntax is tr [options] SET1 [SET2]. tr takes no
file names; input comes from a pipe or a redirection with <.
Sets can contain ranges such as a-z, escapes such as
\n and \t, and character classes such as
[:digit:]. Quote the sets so that the shell does not interpret
them. The examples use GNU tr from coreutils.
Changing case
Translating the range of lowercase letters to uppercase letters converts text to uppercase.
tr a-z A-Z < text.txt tr '[:upper:]' '[:lower:]' < text.txt
Each character of the first set is replaced with the character at the same
position in the second set. The character classes [:upper:] and
[:lower:] express the same intent more clearly.
$ tr a-z A-Z < text.txt THE QUICK BROWN FOX. THE LAZY DOG! $ tr '[:upper:]' '[:lower:]' < text.txt the quick brown fox. the lazy dog!
Translating characters
The two sets map characters one to one.
echo 'hello world' | tr 'lo' 'xy' echo 'hello world' | tr 'a-y' 'b-z' echo 'hello world' | tr 'a-z' 'x'
In the first command, l becomes x and
o becomes y. Note that tr works with
individual characters, not strings: it cannot replace the word
lo with xy; use sed for that. The
second command shifts each letter by one. If the second set is shorter, GNU
tr repeats its last character, so in the third command all
letters become x.
$ echo 'hello world' | tr 'lo' 'xy' hexxy wyrxd $ echo 'hello world' | tr 'a-y' 'b-z' ifmmp xpsme $ echo 'hello world' | tr 'a-z' 'x' xxxxx xxxxx
Deleting characters
The -d option deletes all characters from the set.
echo 'Phone: +421 (905) 123-456' | tr -d '()+ -' echo 'Order 66 shipped 2026' | tr -d '[:digit:]'
The first command removes parentheses, the plus sign, spaces, and dashes. The dash is placed last in the set so that it is not taken for a range. The second command removes all digits.
$ echo 'Phone: +421 (905) 123-456' | tr -d '()+ -' Phone:421905123456 $ echo 'Order 66 shipped 2026' | tr -d '[:digit:]' Order shipped
Converting Windows line endings
Text files created on Windows end their lines with a carriage return and a line feed (CRLF). Deleting the carriage returns converts them to Unix line endings.
tr -d '\r' < dos.txt > unix.txt
The file command reports the line terminators, and
od -c shows the \r characters before each
\n. After the conversion, they are gone. This fixes scripts that
fail with errors such as $'\r': command not found.
$ file dos.txt dos.txt: ASCII text, with CRLF line terminators $ tr -d '\r' < dos.txt > unix.txt $ file unix.txt unix.txt: ASCII text $ od -c dos.txt | head -n 2 0000000 l i n e o n e \r \n l i n e t 0000020 w o \r \n $ od -c unix.txt | head -n 2 0000000 l i n e o n e \n l i n e t w 0000020 o \n
Squeezing repeated characters
The -s option replaces each run of a repeated character from the
set with a single occurrence.
echo 'too many spaces' | tr -s ' ' echo 'aaabbbccc' | tr -s 'a-c' printf 'one\n\n\ntwo\n' | tr -s '\n'
Squeezing spaces normalizes the spacing between words, which is useful
before splitting text with cut. Squeezing newlines removes
empty lines.
$ echo 'too many spaces' | tr -s ' ' too many spaces $ echo 'aaabbbccc' | tr -s 'a-c' abc $ printf 'one\n\n\ntwo\n' | tr -s '\n' one two
Keeping only selected characters
The -c option uses the complement of the first set, that is,
all characters not in it. Combined with -d, it keeps only the
listed characters.
echo 'User #42: jano@example.com!' | tr -cd '[:alnum:]@.\n'
All characters except letters, digits, the at sign, the dot, and the newline are deleted. We keep the newline in the set; otherwise the trailing newline would be removed as well.
$ echo 'User #42: jano@example.com!' | tr -cd '[:alnum:]@.\n' User42jano@example.com
Splitting into lines
Translating a separator to a newline puts each item on its own line.
echo "$PATH" | tr ":" "\n"
The directories of the PATH variable are printed one per line,
which makes them easy to read or to process further.
$ echo "$PATH" | tr ":" "\n" /usr/local/bin /usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin
ROT13
ROT13 is a simple letter substitution that replaces each letter with the one 13 positions later in the alphabet.
echo 'Hello World' | tr 'A-Za-z' 'N-ZA-Mn-za-m'
Since the alphabet has 26 letters, applying ROT13 twice returns the original text. It hides text from casual reading but provides no security.
$ echo 'Hello World' | tr 'A-Za-z' 'N-ZA-Mn-za-m' Uryyb Jbeyq $ echo 'Hello World' | tr 'A-Za-z' 'N-ZA-Mn-za-m' | tr 'A-Za-z' 'N-ZA-Mn-za-m' Hello World
Word frequency
tr is a key part of the classic word frequency pipeline.
tr -cs '[:alpha:]' '\n' < story.txt | tr '[:upper:]' '[:lower:]' | sort | uniq -c | sort -rn | head -n 5
The first tr replaces every run of non-letters with a single
newline, which puts each word on its own line. The second one converts the
words to lowercase. Then sort groups equal words,
uniq -c counts them, and the final
sort -rn ranks them by frequency.
$ tr -cs '[:alpha:]' '\n' < story.txt | tr '[:upper:]' '[:lower:]' | sort | uniq -c | sort -rn | head -n 5
5 the
3 falcon
2 saw
2 owl
2 old
Limitations
GNU tr works with bytes, not with multibyte characters, and it
does not read files given as arguments.
echo 'čaj' | tr '[:lower:]' '[:upper:]' echo 'café' | tr 'é' 'e' tr a-z A-Z text.txt
The letter č is not converted to uppercase. The character
é consists of two bytes in UTF-8; both are translated, the
second one to the repeated last character of the second set, so we get two
letters e. For non-ASCII text, use sed or a
scripting language. The last command fails because tr accepts
only sets as arguments.
$ echo 'čaj' | tr '[:lower:]' '[:upper:]' čAJ $ echo 'café' | tr 'é' 'e' cafee $ tr a-z A-Z text.txt tr: extra operand ‘text.txt’ Try 'tr --help' for more information.
Best practices for tr
- Quote the sets: Prevent the shell from expanding
*,[, or backslashes. - Use character classes:
[:digit:]or[:space:]are clearer than ranges. - Put the dash last: A dash in the middle of a set creates a range.
- Use sed for strings:
trreplaces single characters only. - Mind the encoding: GNU
trdoes not handle multibyte UTF-8 characters.
Source
In this article, we have used the tr command to change case,
translate, delete, and squeeze characters, convert line endings, and count
word frequencies.
Author
List all Linux tutorials.