13

I am confused regarding the way -s, -t, and -c options work in the tr command. When I do

echo I am a good boy | tr good bad

I get the output:

I am a bddd bdy

This is quite understandable, since o is repeated in good. The last possible change in place of o is d, and hence the output.

Now when I do

echo I am a good boy | tr -s good bad

the output is

I am a bd bdy

The -s option is supposed to squeeze every repeated occurence of each character in set 1 into a single occurence and then change each character in set 1 into the corresponding character in set 2 which is in the same position.

So it should have been

I am a bad bay.

Why the change?

Moreover, when I do

echo I am a good boy | tr -c good bad

I get dddddddgoodddodd

How does the -c option work for tr, referring to this example?

And finally: how to change myself from a good boy to a bad boy.... :) :P That is,

echo I am a good boy | tr <something> gives me the output as: I am a bad boy.

1
  • Does anyone know what [=CHAR=] means in a set? The man page says "all characters which are equivalent to CHAR". But I am not sure what that means. Does [=?=] mean all punctuation and [=a=] mean all lowercase letters, etc? – Yetti99 Nov 24 '20 at 18:01
13

-s Switch: Squeeze (remove repeated characters)

echo i am a good boy | tr -s good bad

output: i am a bd bdy

There are two things happening behind the scenes that make this happen. Firstly, if the second argument to tr is shorter than the first then the last character in the 2nd arg is repeated to make it the same length as the first. So the equivalent command is:

echo i am a good boy | tr -s good badd

The other thing that is happening is when characters in the first argument are repeated they overwrite any previous occurrence (I'm referring to the two oos in good). This makes the command now equivalent to:

echo i am a good boy | tr -s god bdd

(the second o to d replacement overwrites the previous o to a replacement, making it redundant)

Without the -s switch the output would be

i am a bddd bdy

With the -s switch tr 'squeezes' any repeated characters that are listed in the last argument leaving the final output:

i am a bd bdy

-c Switch: Complement

The -c switch is used to match the complement of the first argument (i.e. all characters not listed in arg 1). As a result, arg 1 will contain many letters (256-3). Now, the same thing happens to arg 2 as in the previous case: Arg 2's final character gets repeated to match the length or Arg 1. So the original statement:

echo i am a good boy | tr -c good bad

is equivalent to:

echo i am a good boy | tr abcefhijklmnp... baddddddddddd...

(note the missing g, o and d in the first set, also note that d will replace every other character in the second set -- including the space character)

This is why i am a good boy turns into dddddddgoodddodd

More info here: http://www.linuxjournal.com/article/2563

1
  • Generally correct, except that the -s switch causes tr to squeeze any characters from the last argument to tr (not the first, as you say) that are repeated in the input. This is noted in the article you linked, and is explained in the last paragraph in the "Description" section of the man page. – ravron Feb 28 '19 at 18:33
4

Your understanding of -s is incorrect, it replaces repeated occurrences of characters in set 1 in the input with a single character. it does not modify the set, eg.

echo i am a good boy | tr -s god bad

gives

i am a bad bay

The -c option replaces set 1 with its complement (ie. the set of all characters not contained in set 1). You can use this to remove all but the specified characters for example.

echo i am a good boy | tr -cd gobdy

outputs

goodboy
1
  • :I got your point regarding -s option, but my question is , how : echo i am a good boy | tr -s good bad is giving output as: i am a bd bdy this is only possible when this happens : first i am a good boy is changed to i am a bddd bdy then the -s option changes the occurences of multiple d's to single i.e: i am a bddd bdy then changes to i am a bd bdy is this what actually is happening ? please break this down for me, same with -c option how is echo i am a good boy | tr -cd gobdy giving this: goodboy – Siddharth Nov 9 '11 at 14:51
1

The other answers covered tr's -s, -t, and -c options but for completeness:

You are having trouble because you picked up the wrong tool.

  • tr is for character transformations
  • sed is for stream editing.

Since both good and bad are sequence of characters in the stream sed is a better match.

echo I am a good boy | <something> gives me the output as: I am a bad boy

$ echo I am a good boy | sed s/good/bad/g
I am a bad boy

The s/..../..../ is Substitute. Whatever matches the first regular expression will be replaced with the second one. The /g flag at the end is for Global replacement this way all occurrences will be replaced not just the first.

$ echo I am a good boy and a good boy is me. | sed s/good/bad/
I am a bad boy and a good boy is me.

$ echo I am a good boy and a good boy is me. | sed s/good/bad/g
I am a bad boy and a bad boy is me.
0

yes. exactly!

tr -s replaces instances of repeated characters with a single character.

(via man page.)

so, it goes like this:

it converts good to bddd. repeated instances are 3 'd's.

so it replaces these three instances with a single instance.

that is it makes it bd. :)

1
  • 2
    We don't expect every answer to be perfect, but answers with correct spelling, punctuation, and grammar are easier to read. – Ashildr Oct 11 '13 at 11:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.