I am trying to write a script that basically searches recursively using find (or another method to) to find all files ending with *.p or *.w but does not contain sysvars.i or preprocess.i

Is find the best command to use?

closed as unclear what you're asking by Kusalananda, n.st, Thomas, GAD3R, Jeff Schaller Nov 25 '18 at 22:09

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 5
    Do you mean that the name should not contain "sysvars.i" etc. or there should be no such strings in the content of the files? – rozcietrzewiacz Aug 1 '11 at 11:43

You can combine the actions of find and grep to accomplish this:

find /search/path/ -type f \( -name '*.p' -or -name '*.w' \) \
    -exec grep -L -e 'sysvars.i' -e 'preprocess.i' {} +

Let's break that down.

  • find /serch/path returns all files in the specified path. Next wee need to narrow that down starting with the things that will eliminate the most matches first to save time checking the other things later.
  • -type f returns only files. If you happened to have directories matching the file name pattern, we don't want to send them to grep.
  • \( [expr1] -or [expr2] \) creates an either/or match so that find returns files that metch either expr1 or expr2 but there is no reason it has to match both. The parenthesis help separate this or group from the rest of the matching options that are actually and requirements.
  • -name '*.p' and -name '*.w' are pretty obvious, return files matching those name patterns.
  • -exec command {} + will run the specified command and any arguments with the {} bit replaced with arguments for each file matched by the rest of the find command. The -exec function is preferable to using xargs or piping to a loop because it handles quoting and file name issues so well.
  • grep is used to search for a pattern in the specified files.
    • -L is used to return just a list of file names that do not have matches
    • -e 'PATTERN' is specified twice to list the two search strings you did not want to match.
  • That didn't work gave me find {-H} -{L} path-list predicate list – colin Aug 1 '11 at 12:47
  • Now tried to use the following code:- – colin Aug 1 '11 at 12:49
  • @colin: Can you answer @rozcietrzewiacz's comment on your question so that we know if we understood your question correctly or not? Did you read the explanation for this command and did it all make sense? Perhaps you see something in there that isn't actually what you wanted to accomplish, hence the empty results. Also, are you sure there are files to be found that match all those criteria? Try taking out just the -v on the grep and see if that returns the files that do have that string. Try removing the entire -exec section to see what find is returning as far as files to be searched. – Caleb Aug 1 '11 at 12:51
  • 1
    I've never done anything more with grep before, than the simplest of simple patterns; sed has always done what I needed, so I'm on unfamilar ground with its options, but on my Ubuntu system, find -l -v -e doesn't work, and I believe it will only work when every line in a file matches the pattern... However grep -L -e 'sysvars.i' -e 'preprocess.i' works... – Peter.O Aug 1 '11 at 15:43
  • 1
    @fred and Caleb: grep -L is not at all the same as grep -lv. grep -L finds files that have no matching line. grep -lv finds files that have at least one non-matching line. – Gilles Aug 1 '11 at 21:19

It's possible to build complex boolean expressions of find tests:

find . \( -name '*.p' -or -name '*.w' \) -and \
  -not \( -name 'sysvars.i' -or -name 'preprocess.i' \)

Posix compliant options names are -a, -o and ! instead of -and, -or and -not.

If you need to look for strings inside files contents, then you must use find along with grep (for example).

  • 1
    The short form of not is -!, not !. The latter refers to command history (by shell expansion). – rozcietrzewiacz Aug 1 '11 at 11:45
  • Ok, so you must be looking for sysvar.i and preprocess.i inside file contents, or the filtering would be useless :-) – Stéphane Gimenez Aug 1 '11 at 11:46
  • 2
    I think the OP was wanting to find files that did not contain those strings. This command doesn't make any sense because matching for the names *.[pw] would already exclude the names (sysvars|preprocess).i. – Caleb Aug 1 '11 at 11:49
  • 1
    @rozcietrzewiacz: No, not if used alone. You may escape it with \! if you wish. "The POSIX standard specifies parentheses '(', ')', negation '!' and the and and or operators ('-a', '-o')". – Stéphane Gimenez Aug 1 '11 at 12:00
  • 1
    Voting for removing this answer and the following discussion if the OP's question turns out being related with file contents. – Stéphane Gimenez Aug 1 '11 at 12:09

Not the answer you're looking for? Browse other questions tagged or ask your own question.