tr is a small command-line tool for changing text one character at a time. It can translate characters, delete them, or collapse repeated characters—but it does not replace words or edit files in place.
That makes it useful in pipelines: pass text to standard input, transform it, and send the result to the terminal or another command.
Start with a translation
The basic form is:
tr [OPTION]... SET1 [SET2]
To map characters in SET1 to the corresponding characters in SET2, provide both sets. For example, convert lowercase letters to uppercase:
printf 'hello, linux\n' | tr '[:lower:]' '[:upper:]'
Output:
HELLO, LINUX
The POSIX character classes [:lower:] and [:upper:] express the intent more clearly than a range such as a-z. Quote sets so the shell passes them to tr as intended.
Translation is positional and character-by-character. This example maps a to 1, b to 2, and c to 3:
printf 'cab\n' | tr 'abc' '123'
The result is 312. For replacing longer strings or matching patterns, use a tool designed for that job; tr only works on individual characters.
Read from a file without changing it
tr does not accept a filename as an input operand. Use shell input redirection to feed a file into it:
tr '[:upper:]' '[:lower:]' < input.txt
This prints the transformed contents; input.txt stays unchanged. To save the result, redirect to a different file:
tr '[:upper:]' '[:lower:]' < input.txt > output.txt
Do not redirect output to the same file you are reading. The shell can truncate the destination before tr gets a chance to read it. If you need a refresher on inspecting file contents or combining files, see this guide to the Linux cat command.
Delete or keep selected characters
Use -d to delete every character that belongs to a set. This removes digits but leaves punctuation and spaces in place:
printf 'order 58: item 204\n' | tr -d '[:digit:]'
Output:
order : item
To do the opposite—keep digits and remove everything else—combine -d with -c, which complements the set:
printf 'order 58: item 204\n' | tr -cd '[:digit:]\n'
Output:
58204
The newline is included in the set so the output retains a line ending. Here, [:digit:] matches individual digit characters, not a whole number as a unit.
Squeeze repeated characters
The -s option reduces each run of repeated characters in a set to one character. To collapse multiple spaces:
printf 'too many spaces\n' | tr -s ' '
Output:
too many spaces
You can also translate tabs and spaces to a single space, then squeeze the result:
printf 'red\t\tblue\n' | tr -s '[:blank:]' ' '
[:blank:] matches horizontal blanks such as spaces and tabs. With translation enabled, -s squeezes repeated characters from the translated set (SET2). The newline is not a blank, so it remains intact.
A quick way to choose an operation
| Goal | Pattern | Effect |
|---|---|---|
| Translate | tr 'abc' '123' |
Map characters by position |
| Delete | tr -d '[:digit:]' |
Remove characters in the set |
| Keep only a set | tr -cd '[:digit:]\n' |
Delete characters outside the set |
| Squeeze | tr -s ' ' |
Collapse repeated spaces |
These operations compose naturally with other filters. For example, you might normalize or remove characters before searching; the Linux grep guide covers the search step and common pattern-matching options.
Portability and text encoding notes
Common character classes include [:digit:], [:lower:], [:upper:], and [:blank:]. Quoted ranges such as 'a-z' are also common, but range ordering can depend on locale. Prefer character classes for case conversion when they express what you mean.
Behavior around locales, complements, and multibyte characters can differ between implementations. GNU tr provides -C to complement characters rather than bytes; do not assume that option is available everywhere. If byte-versus-character behavior matters, check the local tr manual page.
For predictable ASCII-oriented processing, you can run a command under the C locale:
LC_ALL=C tr '[:lower:]' '[:upper:]'
That changes how the utility interprets input, so use it when ASCII-oriented behavior is appropriate—not as a universal fix for arbitrary text.
One final distinction is worth remembering: tr writes transformed output to standard output. It is a filter, not an in-place editor. Use it in a pipeline or redirect its output deliberately, and choose a separate destination file when preserving the original matters.
I originally published a more detailed version of this guide on the SSHFlow blog.
I'm also building SSHFlow — an SSH client where every server gets its own workspace for terminals, SFTP, code, and databases.
Top comments (0)