0

Create files

touch a1.txt a2.txt a3.txt
touch s1.mp3 s2.mp3 s3.mp3

then I do

find . -name "*.txt" -or -type f -print

And it's showing only s1.mp3 s2.mp3 s3.mp3. Why it's not showing .txt files?

2 Answers 2

7

Because of the precedence of the operators: the implicit AND (-a) between -type f and -print has higher precedence than the OR (-o); your command is similar to

find . \( -name "*.txt" \) -or \( -type f -print \)

while you probably want

find . \( -name "*.txt" -or -type f \) -print

to print all the files.

0

The precedence is only half of the answer. What matters is also how the rules for finishing the boolean expressions work. This soon gets a bit complicated, mostly becasue find uses sane defaults and is programmable at the same time.

To illustrate what I mean, here is another solution:

find . -name "*.txt" -print -or -type f -print

this adds an explicit action to every end-point. And just:

]# find -name "*.txt" -or -type f
./p.txt
./s1.mp3
./a1.txt

also gets all files (including the non-regular "p.txt" entry). Here the default -print is outside any (sub-)expression and is applied for all branches.

After adding exactly one -print, you get "either...or":

]# find -name "*.txt" -print -or -type f 
./p.txt
./a1.txt

]# find -name "*.txt" -or -type f -print
./s1.mp3

No use deabating which is better - problem is the Q is very artificial (and also duplicate). If somebody wants to track down a mkfifo pipe.txt, a logical 'AND NOT' instead of 'OR' would make more semantic (and overall) sense.

For this, you need neither parens nor -print:

]# find -name "*.txt" -not -type f       
./p.txt

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .