Why can't I find some matches?

I am writing several bash / zsh scripts that process some files. I want to execute a command for each file of a certain type, and some of these commands overlap. When I try to find -name 'pattern1' -or -name 'pattern2' , only the last pattern is used (files matching pattern1 are not returned, only files matching pattern2 ). I want the files to match either pattern1 or pattern2 .

For example, when I try to do the following, this is what I get (note only ./foo.xml found and printed):

 $ ls -a . .. bar.html foo.xml $ tree . . ├── bar.html └── foo.xml 0 directories, 2 files $ find . -name '*.html' -or -name '*.xml' -exec echo {} \; ./foo.xml $ type find find is an alias for noglob find find is /usr/bin/find 

Using -o instead of -or gives the same results. If I switch the order of the -name options, only bar.html , not foo.xml .

Animated version

Why are bar.html and foo.xml not found and returned? How can I match multiple patterns?

+6
source share
2 answers

You need to use parentheses in your find to group your conditions, otherwise only the 2nd -name acts for the -exec command.

 find . \( -name '*.html' -or -name '*.xml' \) -exec echo {} \; 
+8
source

find utility

-print == default

If you just want to print the path and file names, you need to abandon exec echo because -print by default .:

 find . -name '*.html' -or -name '*.xml' 

Depends on the order

Otherwise, find is read from left to right, the order of the arguments is important!

So, if you want to indicate something, observe and and or priority:

 find . -name '*.html' -exec echo ">"{} \; -o -name '*.xml' -exec echo "+"{} \; 

or

 find . -maxdepth 4 \( -name '*.html' -o -name '*.xml' \) -exec echo {} \; 

Expression -print0 and -print0 command.

But for most cases, you can consider -print0 with the -print0 command, for example:

 find . \( -name '*.html' -o -name '*.xml' \) -print0 | xargs -0 printf -- "-- %s -\n" 

The advantage of this is as follows:

  • Only one (or several) plugs for thousands of records found. (Using -exec echo {} \; implies that one subprocess is started for each entry, and xargs build a long line with as many arguments as one command line could contain ...)

  • To work with file names containing a special character or space, -print0 and -print0 xargs -0 will use the NULL character as a file name separator.

find ... -exec ... {} ... +

A few years ago, the find adopted a new syntax for the -exec switch.

Instead of \; The -exec switch may end with a plus sign + .

 find . \( -name '*.html' -o -name '*.xml' \) -exec printf -- "-- %s -\n" {} + 

Using this syntax, find will work as an xargs command, creating long command lines to reduce forks.

+3
source

Source: https://habr.com/ru/post/981998/


All Articles