The find -o Bug Almost Everyone Writes (and the One-Character Fix)
ProductionDevOps
0:00 / 0:00
The find -o Bug Almost Everyone Writes (and the One-Character Fix)
11 просмотров · 1 день назад
ProductionDevOps
3 подписчика
11 просмотров · 1 день назад
find . -type f -name A -o -name B looks like it searches for files named A or B. It does not. Step by step, we reproduce the bug on a real folder, see the invisible AND that find adds, fix it with parentheses, and look at the second trap: actions like -print that only apply to the last branch.
▶ Code and commands for this video: https://github.com/production-devops-lab/d...
Part 2 of 3 · Command Anatomy: Linux & DevOps Commands Explained Piece by Piece
▶ Full series: • Command Anatomy: Linux & DevOps Commands E...
◀ Previous: Anatomy of a Production-Ready podman run (Every Flag Explained) – • Anatomy of a Production-Ready podman run (...
▶ Next: Stop Scrolling kubectl Output: custom-columns, jsonpath and --sort-by – • Видео
Chapters:
0:00 Intro
0:15 The plan
0:36 The test folder
0:57 The bug
1:31 The invisible AND
2:20 The fix
2:44 The second trap
3:16 Recap
Full transcript:
This find command looks like it searches for files with one name or another. It actually does something different, and in a script it can pass the wrong paths to the next command. Let's see it happen, step by step.
== The plan ==
Here is the plan.
First, we look at a small test folder.
We run the command, and spot the wrong result.
We see why it happens: an invisible AND that find adds for you.
We fix it with parentheses, and look at a second trap with dash print.
== The test folder ==
This is everything in our folder. find with only a dot lists every path.
$ find . | sort
Look at the paths. Two journal files under logs. Under conf, a file called journald dot conf, and a folder called journald dot conf dot d. Remember that folder.
== The bug ==
Our goal: find every regular file, whose name ends in dot journal, or contains the word journald. Dash type f means regular files only. Dash o means OR.
$ find . -type f -name '*.journal' -o -name '*journald*'
Four results. But look at the third one: journald dot conf dot d. That is the folder. Let's make sure.
$ ls -ld conf/journald.conf.d
The d at the very start of the line means directory. We asked for files only, and still got a folder. Why?
== The invisible AND ==
What you type:
-type f -name '*.journal' -o -name '*journald*'
What find reads:
-type f -a -name '*.journal' -o -name '*journald*'
How find groups it:
( -type f -a -name '*.journal' ) -o ( -name '*journald*' )
This is what we typed: two tests, then dash o, then one more test.
Between two tests with nothing in between, find adds an invisible dash a. Dash a means AND.
And AND is stronger than OR. Just like in math, where you multiply before you add. So find makes two groups. On the left: a regular file AND a journal name. On the right: only the name test.
So each path takes this route. If it is a regular journal file, it is printed. If not, find tries the right side, which only checks the name. Our folder has journald in its name, so it is printed, even though it is a folder. The type check only lives on the left side.
== The fix ==
The fix: put the two name tests inside parentheses, so dash type f applies to both. The parentheses need a backslash in front, so the shell passes them to find, instead of using them itself.
$ find . -type f \( -name '*.journal' -o -name '*journald*' \)
Three results, all regular files. The folder is gone. This is what we meant from the start.
== The second trap ==
Same rule, second trap. Now we add dash print at the end. We expect the journal files and the conf files.
$ find . -name '*.journal' -o -name '*.conf' -print
Only one line. Dash print is an action, and it was glued with an invisible AND to the last test only. The journal files matched the left side, but nothing told find to print them.
Same fix: parentheses around the OR, then the action after them.
$ find . \( -name '*.journal' -o -name '*.conf' \) -print
== Recap ==
Let's recap with three rules.
One. Every time you write dash o, wrap the alternatives in escaped parentheses.
Two. Actions like print, exec or delete go after the closing parenthesis.
Three. Before you delete anything with find, run the same expression with print, and read the list.
Two escaped parentheses are the difference between the files you meant and the paths you got. Check the find commands in your own scripts today. Subscribe for more commands, explained piece by piece.
Links:
GitHub: https://github.com/production-devops-lab/d...
Work with me: https://production-devops-lab.github.io
Business enquiries: production-devops@proton.me
#find #linux #bash