aboutsummaryrefslogtreecommitdiff
path: root/src/blog/2024-01-13-tr/tr.md
blob: d5917b5156b1cf3c6f17a24555d964fe63bdf254 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# UNIX text filters, part 2.1 of 3: tr

*This post is part of a [series](../../series)*

In the [post about sed](../2023-12-03-sed) I have not discussed the
`y` command at all. This is because I realized it is just an
underpowered version of the `tr` command, that we are going to
explore in this post.

The `tr` command is a simple utility that can perform
character-by-character substitutions and a couple of other things.
Like most UNIX utilities, it operates on standard input and standard
output by default.

## Replacing

The most basic form of a `tr` command is

```
$ tr string1 string2
```

which replaces every occurrence of a character present in `string1`
with its corresponding character in `string2` - the first with the
first, the second with the second and so on. If `string2` is shorter
than `string1`, the last character is repeated as needed.

For example

```
$ echo 'Hello!' | tr le 13
H311o!
```

An equivalent `sed` command would be `sed 'y/le/13/'`.

Like sed and [grep](../2023-08-20-grep), also `tr` supports the
standard character sets like `[:upper:]`, `[:alpha:]` and so on.
For example, the following command capitalizes every letter in the
input string:

```
$ echo 'Hello!' | tr [:lower:] [:upper:]
HELLO!
```

## Deleting

With the `-d` option one can delete characters:

```
$ echo 'R42emo3vin0g all n66umber3s!' | tr -d 0-9
Removing all numbers!
```

Here I have used the *character range* `0-9` instead of `[:digit:]`.
Other examples of valid character ranges are `A-Z`, `0-8` and `a-f`.

The `-d` option can be combined with the `-c` option, which takes
the *complement* of a given set of characters:

```
$ echo 'R42emo3vin0g all non-n66umber3s!' | tr -cd '0-9\n'
4230663
```

Notice that I have also added `\n` to our list of
characters, so that the newline at the end of the text is kept.

A more complex example involving `tr -cd` is the following, which
I use to generate random passowrds:

```
$ cat /dev/random | tr -cd 'a-z0-9' | fold -w 12 | head -n 1
ft82mtfsy5ps
```

Here `/dev/random` spits out random data, while the commands
`fold -w 12` and `head -n 1` are used to break the input text into
lines of 12 characters and take the first line of the input,
respectively.  We'll talk about them in future posts.

## Squeezing

One more thing `tr` can do is *squeezing* consecutive identical
characters.  For example:

```
$ echo Helllllo | tr -s l
Helo
```

The `-s` option can be combined with the `-c` or `-d` option, and
in this case the squeezing is performed last, squeezing all the
characters contained in the last given string:

```
$ echo 'Hellllo! 112233' | tr -s 'l_e' '123'
H31o! 123
$ echo 'Hello!' | tr -ds '!' 'l'
Helo
```

## Conclusions

This is pretty much all there is tu say about `tr`. All of this can
probably be done with a sufficiently complicated `sed` or `awk`
script, but it is definitely nice to have a simpler utility to perform
easy changes.

*Next in the series: [head and tail](../2024-02-20-head-and-tail)*

Generated with cgit - Back to sebastiano.tronto.net