aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/blog/2023-08-20-grep/grep.md247
1 files changed, 247 insertions, 0 deletions
diff --git a/src/blog/2023-08-20-grep/grep.md b/src/blog/2023-08-20-grep/grep.md
new file mode 100644
index 0000000..18c69bf
--- /dev/null
+++ b/src/blog/2023-08-20-grep/grep.md
@@ -0,0 +1,247 @@
1# Unix text filters, part 1 of 3: grep
2
3After [the preliminary post on regular expressions](../2023-06-16-regex),
4we are ready to begin this series on *text filters*.
5
6This time we'll explore `grep`, the most simple kind of filter:
7given a bunch of lines of text, print out only those that match a
8certain criterion.
9
10I will only describe a few basic options. All that I mention here
11is POSIX-standard, with the exception of the option `-o`. This means
12that the content of this post is valid in pretty much any UNIX-like
13OS, but check your manual pages before copy-pasting my code - I can
14always make mistakes.
15
16Without further ado, let's dive in!
17
18## Standard usage
19
20If you are familiar with how (UNIX) programs read from standard
21output and write to standard output, the idea behing `grep` is
22easily explained: the command
23
24```
25$ grep PATTERN
26```
27
28will read lines from standard input and write to standard output
29only those that contain the given `PATTERN`. If you specify file
30names after the pattern
31
32```
33$ grep PATTERN file1 file2 ...
34```
35
36`grep` will read those files instead of standard input. The `PATTERN`
37can also be a [regular expression](../2023-06-16-regex).
38
39In other words, you can use `grep` to look for certain pieces of
40text in a file or in the output of another command. If you do not
41understand all of this is about, start reading from the **Examples**
42section below to get an idea.
43
44Now let's see how you can tune `grep`'s behavior to your needs.
45
46### What to match: `-i`, `-v`
47
48A common use of `grep`, especially for non-programming tasks, is
49to look for occurrences of a specific word in a long text. In
50this case one usually does not care if the word is all lowercase
51or capitalized, for example because at the beginning of a sentence.
52If you find yourself in this situation, you can use the `-i` option
53to make `grep` case-insensitive.
54
55Sometimes it easier to spell out what you *do not* want to match -
56for example, say you want all non-empty lines of a given file. In
57this case you can use the `-v` option to invert the behavior of
58`grep`, such as:
59
60```
61$ grep -v "^$" file
62```
63
64Here `"^$"` is a regular expression that matches all lines where the
65beginning of the line (in regex language, `^`) is immediately followed
66by the end of the line (`$`); in other words, empty lines.
67
68### More on patterns: `-E`, `-e`, `-F`, `-f`
69
70Up to now I have not specified what *kind* of regular expression
71`grep` uses. By default it uses basic regular expressions, but it
72uses extended regular expressions if called with the `-E` option.
73Equivalentrly, you can use the command `egrep`. If you want to
74turn off regular expressions altogether, you can use `grep -F` (or
75`fgrep`).
76
77If you want to select lines that match *any* of a number of patterns,
78you can use the `-e` option:
79
80```
81$ grep -e PATTERN1 -e PATTERN2 -e ... [file1 file2 ...]
82```
83
84Alternatively you can write your pattern in a file, one per line,
85and use:
86
87```
88$ grep -f PATTERN_FILE [file1 file2 ...]
89```
90
91### Grepping multiple files: `-l`, `-n`
92
93Sometimes I use `grep` to find occurrences of a certain string in
94a bunch of files, for example with
95
96```
97$ grep "word" *
98```
99
100When used with multiple input files like this, `grep` will precede
101each output line with the name of the file that contains it. If the
102option `-n` is used, the line number is also shown. If `-l` is used,
103only the name of the file is shown, and each file is shown at most
104once.
105
106If you do not want to print the file names at all, you can always
107`cat` into `grep`:
108
109```
110$ cat file1 file2 ... | grep
111```
112
113But if anyone asks, you did not learn this from me - UUOC (Useless
114Use Of Cat) is a considered a crime in some circles.
115
116### Matching only part of a line: `-o`
117
118You may not always want the *full line* containing a piece of text.
119Sometimes you just want a specific part of a line, and you know
120exactly how to match it with a regular expression. In this case you can
121use the `-o` option - we'll see an example below.
122
123The `-o` is not POSIX-standard. It is ubiquitous though, and it
124should be present in pretty much any version of `grep`.
125
126## Examples
127
128Now that we now the basics, let's see some exciting applications
129of `grep`!
130
131Nah, I am kidding, they are not exciting. But they are useful. Boring,
132but useful.
133
134### Filter command output
135
136Probably my first use of `grep` was to filter out irrelevant part of
137some command's output. Say for example you are troubleshooting a
138problem with your webcam: you can use `dmesg` to check what your
139operating system knows about it, but most of the output is useless
140to your specific problem. No worries, you can pipe `dmesg` into
141`grep`:
142
143```
144$ dmesg | grep video
145acpivideo0 at acpi0: VGA_
146acpivout0 at acpivideo0: LCDD
147uvideo0 at uhub0 port 6 configuration 1 interface 0 "JMICRON TECHNOLOGIES CO., LTD. USB2.0 UVC VGA WebCam" rev 2.00/2.04 addr 2
148video0 at uvideo0
149```
150
151### Look stuff up in files
152
153Sometimes you may want to search something in a bunch of files.
154Let's say for example I want to check in which of my old blog posts
155I have mentioned "Linux":
156
157```
158$ grep -l Linux src/blog/*/*
159src/blog/2022-05-29-man/man.md
160src/blog/2022-08-14-website/website.md
161src/blog/2022-09-10-netbooks/netbooks.md
162src/blog/2023-01-28-windows-desktop/windows-desktop.md
163src/blog/2023-02-25-job-control/job-control.md
164src/blog/2023-02-25-job-control/jobs-diagram.pdf
165```
166
167Or say I am working on one of my software projects, and I do not remember where
168a certain function is defined:
169
170```
171$ grep -n "^apply_move(" src/*.c
172src/moves.c:206:apply_move(Move m, Cube cube)
173```
174
175*Note: the command above works because, when I write C code, I write
176function names on a newline. See also
177[this older post](../2022-06-12-shell-ide-sed) for another example
178that takes advantage of this, this time using `sed`.*
179
180### Grepping URLs
181
182Looking for URLs in a piece of text is a common enough operation
183for me that I saved it into a [script](https://git.tronto.net/scripts)
184for ease of use, that I called `urlgrep`. URLs can be complicated,
185so for a long time I used a regular expression copied from somewhere
186on the internet.
187
188Now now that I am more familiar with `grep` and regular expressions, I have
189written my own - it does not work perfectly, but at least I understand it
190and I can keep tweaking it if I find errors.
191
192Let's build it together! What does a URL look like? It usually starts with
193either a *protocol* followed by a colon, or with `www.`. Then a bunch of
194valid characters follow. There are probably more rules to it, but to keep
195is simple we can start like this (using *extended* regular expressions):
196
197```
198regex="(($protocols):|www\.)[$valid_chars]+"
199```
200
201For protocols we can use
202
203```
204protocols='http|https|ftp|sftp|gemini|mailto'
205```
206
207I have thrown `mailto` in there because it is quite common in links web
208pages. The valid characters are:
209
210```
211valid_chars="][a-zA-Z0-9_~/?#@!$&'()*+=.,;:-"
212```
213
214(Yes, these ones I actually copied somewhere online). Finally we can
215find all URLs with
216
217```
218$ egrep -o "$regex"
219```
220
221As I mentioned above there are some problems with this. For example
222if a URL is not terminated by a space, the characters following it
223may be grepped too. For example:
224
225```
226$ urlgrep <src/blog/2022-05-21-blogs/blogs.md
227https://en.wikipedia.org/wiki/Hypertext).
228https://caseymuratori.com/blog_0031)
229https://en.wikipedia.org/wiki/Netbook)
230https://developer.mozilla.org/en-US/Learn)
231https://www.romanzolotarev.com/website.html).
232```
233
234This is not *technically* a problem, because parentheses and dots are allowed
235as part of a URL. But it is *practically* a problem, because most URLs will
236only contain matching pairs of parentheses.
237
238## Conclusion
239
240`grep` is a must-know for anyone who wants to be proficient with the
241UNIX command line. Luckily, it is also pretty easy to learn.
242
243Moreover, being familiar with `grep` makes it easy to learn more
244advanced tools, such as `sed` and `awk`: the "read one line, process
245it, print something" idea is common to all three of them.
246
247Stay tuned for the part 2: `sed`!

Generated with cgit - Back to sebastiano.tronto.net