-1

I was playing around with tr and got some unexpected results. What is happening in these situations? I don't understand what is happening under the hood, or perhaps I'm not using this command correctly.

Example A

echo '0123456789' | tr [:digit:] '12'

1222222222


Example B1

echo '1111111111' | tr [:digit:] '12'

2222222222

Example B2

echo '1111111111' | tr '1' '12'

1111111111


Example C1

Works as expected.

echo '0123456789' | tr '5' 'x'

01234x6789

Example C2

I expected this to produce 01234xx6789 maybe, or it somehow explains all these examples - in that only the original character can be replaced (additional characters cannot be added).

echo '0123456789' | tr '5' 'xx'

01234x6789

BadHorsie
  • 141
  • What are the names of the files in the current directory and what shell are you using? You are using the [:digit:] pattern unquoted, so the shell will replace it with any matching filename before calling tr. – Kusalananda Nov 22 '23 at 15:59
  • There are no relevant files, but I see your point. I was testing at the time to see if quoting was necessary and how I would replace the actual string '[:digit:]' if I wanted to (escaping the first [ seems to do the trick). – BadHorsie Nov 22 '23 at 16:02

2 Answers2

3

tr’s arguments are maps of characters: characters are mapped 1:1 in order. In the set of replacements, the last character is repeated as necessary; extra characters are ignored.

Thus

tr 5 x

replaces ‘5’ with ‘x’, as expected.

tr 5 xx

replaces ‘5’ with ‘x’, too; the extra ‘x’ is ignored.

tr 1 12

“replaces” ‘1’ with ‘1’; the extra ‘2’ is ignored.

tr '[:digit:]' '12'

quoted to avoid expansion by the shell, is equivalent to (depending on locale)

tr 0123456789 122222222

and replaces ‘0’ with ‘1’, and ‘1’ to ’9’ with ‘2’.

Stephen Kitt
  • 434,908
1

IMO this behavior is explained perfectly in the macos tr man page:

In the first synopsis form, the characters in string1 are translated into the characters in string2 where the first character in string1 is translated into the first character in string2 and so on. If string1 is longer than string2, the last character found in string2 is duplicated until string1 is exhausted.

jesse_b
  • 37,005