A Little Devil Called tr

 in
Here's a useful command for translating or deleting characters in a file.

The program called tr is not a big program; it is quite small and not extremely powerful. However, if you write scripts, you will treasure it as one of your favorites. It is a typical script program, reading from stdin and writing to stdout; there are no file names to provide as arguments. The main function is translating characters. A second important function is deleting characters. Furthermore, tr is capable of squeezing repeated characters into one, but that particular function is rarely used.

Let us begin with translating characters. The tr command takes the form:

tr

While tr reads its input, it replaces characters appearing in string1 by the corresponding characters in string2. So, the command tr abc def will replace a line like “the quick brown fox quickly jumped over the lazy dog” into “the quifk erown fox quifkly jumped over the ldzy dog”. Well, that doesn't make sense, but it does demonstrate how tr works.

Have you ever wanted to capitalize or de-capitalize a file? To capitalize it, you can use:

tr abcdefghijklmnopqrstuvwxyz \
        ABCDEFGHIJKLMNOPQRSTUVWXYZ

Luckily, we can also use ranges of characters to specify the characters more efficiently:

tr a-z A-Z
Ever had those horrible upper case DOS file names? Here's a Bourne script to take care of them:
for f in *; do
      mv $f `echo $f | tr A-Z a-z`
   done
Many UNIX editors allow some text to be processed by the shell. For example, to replace all upper case characters of the next paragraph with lower case while in vi, type:
!}tr A-Z a-z
As another example, the command:
!jtr a-z A-Z
capitalizes the current and next line (the character after the ! is a movement character).

If you read the International Obfuscated C Code Contest (ftp://ftp.uu.net./pub/ioccc/), you frequently see that part of the hints are coded by a method called rot13. rot13 is a Caesar cypher, i.e., a cypher in which all letters are shifted some number of places. For example, a becomes b, b becomes c, ..., y becomes z, and z becomes a. In rot13 each letter is shifted 13 places. It is a weak cypher, and to decipher it, you can use rot13 again. You can also use tr to read the text in this way:

tr a-zA-Z n-za-mN-ZA-M

Another interesting way to use tr is to change files from Macintosh format to UNIX format. For returns, the Macintosh uses \r while UNIX uses \n. GNU tr allows you to use the C special characters, so type:

tr \r \n
If you don't have GNU's version of tr, you can always use the corresponding octal numbers as shown here:
tr \015 \012
You might wonder what would happen if the second string is shorter than the first string. POSIX says this is not allowed. System V says that only that portion of the first string is used that has a matching character in the second string. BSD and GNU pad the second string with its final character in order to match the length of the first string.

The reason this last method is handy becomes clearer when we take complements into account. Assume you wish to make a list of all words and keywords in your listing. When you use -c, tr complements the first string. In C, all identifiers and keywords consist of a-zA-Z0-9_, so those are the characters we want to keep. Thus, we can do the following:

tr -c a-zA-Z0-9_ \n

If we pipe the tr output through sort -u, we get our desired list. If we follow POSIX, the second string would have to describe 193 newline characters (described as \n*193 or \n*). If we use system V, only the zero byte is translated to a newline, since the complement of a-zA-Z0-9_ starts with the zero byte.

The second important use of tr is to remove characters. For this option, you use the flag -d with one string as an argument. To fix up those nasty MS-DOS text files with a ^M at the end of the line and a trailing ^Z, specify tr in this way:

tr -d \015\032

Many people have written a program in C to do this same operation. Well, a C program isn't necessary—you only need to know the right program, tr, with the right flags. The -d flag isn't used often, but is nice to have when needed. You can combine it with the -c flag to delete everything except characters from the string you supplied as an argument.

Repeated characters can be squeezed into a single one using the -s option with one string as an argument. It can also be used to squeeze white space. To remove empty lines, type:

tr -s \n

The -s option can be used with two strings as arguments. In that case, tr first translates the text as if -s were not given and then tries to squeeze the characters in the second string. For instance, we can squeeze all standard white space to a single space by specifying:

tr -s   \n [ *]
The -d flag can also be used with two strings: the characters in the first string will be removed and the characters in the second string will be squeezed.

tr may not be a great program; however, it gets the job done. It is particularly useful in scripts using pipes and command substitutions (i.e., inside the back quotes). If you use tr often, you'll learn to appreciate its capabilities. Small is beautiful.

Hans de Vreught (J.P.M.deVreught@cs.tudelft.nl) is a computer science researcher at Delft University of Technology. He has been using UNIX since 1982 (Linux since 0.99.13). He likes non-virtual Belgian beer, and he is a real globetrotter, having already traveled twice around the world.

______________________

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Filtering fields of a file

barun parichha's picture

Here r my set of records in file
File.txt:
1::2:3:4
4:5:6:7:8
7:8:9:10:
7: 8 9:1:2:3
::::

The fields are separated by field separator(:).
I want to print the fields of this record. There are two problems while printing this. 1) some fields are blank(::), 2) Some fields contains more then one characters separated by space character (:8 9:)
Can it be done using tr ?

pleas let me wat it does

Anonymous's picture

tr "(){}[]\"'<>;&@" " " < $data_dir/SCell_$dt.wk > $data_dir/SCell_$dt.sort.init

Re: Take Command: A Little Devil Called tr

Anonymous's picture

I would like to be able to count how many of each letter of the alphabet are in a file, reguardless of case. I'm trying to figure out how to make tr replace EACH letter with the letter followed by a line feed.

Thank you.

Webinar
One Click, Universal Protection: Implementing Centralized Security Policies on Linux Systems

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Learn More

Sponsored by Bit9

Webinar
Linux Backup and Recovery Webinar

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.

Learn More

Sponsored by Storix