>_cmd.script

tr

Translate, squeeze, or delete characters from input

Text Processing

By CMD Script Team · 4 min read · Last updated

SYNTAX
tr [OPTIONS] SET1 [SET2]

Options

Command options and flags
FlagDescription
-dDelete characters in SET1 from the input, no SET2 needed
-sSqueeze consecutive repeated characters in SET1 down to a single instance
-cComplement SET1: operate on all characters NOT in the set
-tTruncate SET1 to the length of SET2 before mapping (GNU tr default behavior)
a-z A-ZCommon character ranges used as SET1/SET2 for case conversion

Distribution compatibility

  • Ubuntu
  • Debian
  • Fedora
  • Arch
  • macOS (BSD tr, character class syntax like [:upper:] is supported the same way)

What it does

tr (translate) reads characters from standard input and, character by character, translates, squeezes, or deletes them according to two character sets you provide. It has no concept of files, lines, or fields — it works purely on the character stream, which makes it fast for simple, uniform transformations like case conversion, stripping unwanted characters, or collapsing repeated characters, but unsuitable for anything pattern- or context-based (that's sed's job).

Beginner examples

  • echo "Hello" | tr 'a-z' 'A-Z' — uppercase all lowercase letters
  • tr -d '0-9' < file.txt — delete every digit from the input
  • tr -s ' ' < file.txt — squeeze multiple spaces into one
  • tr '\n' ' ' < file.txt — replace every newline with a space
echo "CMD Script" | tr 'a-z' 'A-Z'

Advanced examples

  • Strip carriage returns to convert Windows line endings to Unix: tr -d '\r' < windows.txt > unix.txt
  • Keep only alphanumeric characters, deleting everything else with -c (complement): tr -cd '[:alnum:]\n' < messy.txt
  • Flatten a newline-separated list into a comma-separated one: tr '\n' ',' < list.txt | sed 's/,$/\n/'
  • Count word frequency by splitting on whitespace into one word per line first: tr -s ' ' '\n' < file.txt | sort | uniq -c | sort -rn
  • Rot13-encode text using two mapped 26-character ranges: tr 'A-Za-z' 'N-ZA-Mn-za-m' < message.txt
tr -s ' \t' '\n' < document.txt | sort | uniq -c | sort -rn | head

Common mistakes

  • Trying to pass a filename directly to tr (tr 'a-z' 'A-Z' file.txt) — it doesn't accept file arguments; you must redirect input with < or pipe it in.
  • Forgetting -d doesn't need a SET2 — tr -d '0-9' 'x' is a mistake; deletion only takes one character set.
  • Assuming tr understands regular expressions — it only works on literal character sets and ranges (a-z, [:digit:]), not patterns like sed or grep use.
  • Using unequal-length SET1/SET2 for translation without realizing GNU tr truncates SET2 or extends it by repeating its last character, which can produce unexpected mappings.

Tips

  • Use POSIX character classes like [:upper:], [:lower:], [:digit:], [:punct:] instead of raw ranges (A-Z) for correctness across locales.
  • Combine -s and -d in sequence via a pipeline for multi-step character cleanup, since a single tr invocation only applies one transformation.
  • tr -c (complement) is useful for keeping only a known-good character set and deleting everything else, e.g. sanitizing input to alphanumerics.

Best practices

  • Reach for tr only for simple, whole-stream character-level transformations; once you need context, patterns, or per-line logic, switch to sed or awk.
  • Always redirect or pipe input into tr — never expect it to accept a filename argument like most other text tools.
  • Prefer POSIX character classes ([:alpha:], [:space:]) over hardcoded ranges when scripts need to work correctly under different locales.

Try it yourself

A simulated shell with a sample home directory — experiment freely, nothing leaves your browser. Type help to list supported commands.

Real-world use cases

  • Normalizing text case before a case-insensitive comparison in a shell script: [ "$(echo "$input" | tr 'A-Z' 'a-z')" = "yes" ].
  • Cleaning up files transferred from Windows systems by stripping carriage returns: tr -d '\r' < report.csv > report_unix.csv.
  • Quick word-frequency analysis of a text file by splitting on whitespace and counting: tr -s ' ' '\n' < essay.txt | sort | uniq -c | sort -rn.

Common interview questions

  • Why can't you run tr 'a-z' 'A-Z' file.txt directly on a file? tr only reads from standard input; it has no file-argument support, so input must be redirected (< file.txt) or piped in.
  • What's the difference between tr -d and tr -s? -d deletes every occurrence of characters in SET1 from the input; -s squeezes consecutive repeats of characters in SET1 down to a single instance, without deleting isolated occurrences.
  • How would you strip Windows-style line endings from a file using tr? tr -d '\r' < file.txt > file_unix.txt removes the carriage return character, leaving Unix-style line feeds.

Frequently Asked Questions

How do I uppercase or lowercase text with tr?

Use tr 'a-z' 'A-Z' to uppercase, or tr 'A-Z' 'a-z' to lowercase. For portability across locales, prefer tr '[:lower:]' '[:upper:]' with POSIX character classes.

Why does tr only take stdin and not a filename argument?

tr is designed purely as a stream filter — it reads standard input and writes standard output, with no concept of file arguments. Redirect a file in with < file or pipe it: cat file | tr ... or tr ... < file.

How do I delete specific characters from text?

Use -d with the set of characters to remove, e.g. tr -d '0-9' removes all digits, or tr -d '\r' strips carriage returns from Windows-formatted text files.

What does tr -s do?

It squeezes (collapses) consecutive repeats of characters in SET1 into a single occurrence — useful for collapsing multiple spaces into one: tr -s ' ' ' ' < file, or more simply tr -s ' '.

Cheat sheet

Download a quick-reference cheat sheet for tr.