In a BASH shell, I would like to take the lines of a file (eg pattern.txt) and find the files on my system whose names contain the patterns in each line of my file. So, I have the following for loop
for pp in `cat pattern.txt`; do find ./ -iname "*${pp}*" -print0; done
which doesn't find any files when if the first line in pattern.txt doe exist. So how can I fix the above command line?
Note: Each line in my file contains characters [a-zA-Z] only.
3 Answers 3
Here's a safe and Windows-proof way of looking for a bunch of file name patterns retrieved from a file. The approach I've chosen is to process the list of patterns into a find
expression.
find_expression=$(<pattern \
sed -e 's/^/-o\n-iname\n*/' \
-e 's/\r\?$/*/' | # turn each pattern into -o -iname *foo*
tail -n +2) # remove spurious initial -o
set -f # turn off globbing
IFS='
' # split only at newlines
find . \( $find_expression \) -print0
set +f; unset IFS # restore defaults
-
@Gilles... Some people like crossword puzzles. I like trying to work out your scripts :) I think I'm starting to recognize your pattern :) ... you are allowing a single invocation of
find
to handle the umpteen (maybe thousands) of args, versus callingfind
unpteen times... The IFS pulls the multi-line output back to a string of args in the form:-iname *abc*
, each seperated by-o
(which I assume means "or")... Howerver I am a bit puzzled by\( \)
.. are they a feature of the shell to group the args, or are they a specific requirement offind
?...(the puzzle is almost solved.. :)Peter.O– Peter.O2011年04月02日 10:10:16 +00:00Commented Apr 2, 2011 at 10:10 -
@fred.bear:
\(
and\)
are passed tofind
as(
and)
respectively; the only shell feature used there is the backslash to quote the next character (so that the parentheses are not interpreted as such by the shell). The rest isfind
expression syntax:(
and)
for expression grouping,-o
as the binary "or" operator.Gilles 'SO- stop being evil'– Gilles 'SO- stop being evil'2011年04月02日 11:17:54 +00:00Commented Apr 2, 2011 at 11:17
Try this:
#!/bin/bash
while IFS= read -r pp; do
find . -iname "*${pp}*" -print0
done < /path/to/pattern.txt
Not sure why you want -print0
, but I left it in anyway. Perhaps you are attempting to pipe this to xargs
?
-
Thanks for the suggestion but the find command still doesn't find anything.Azim– Azim2011年04月01日 21:45:21 +00:00Commented Apr 1, 2011 at 21:45
-
Yes at the end I will pipe the results to xargs to copy the files it finds.Azim– Azim2011年04月01日 21:46:59 +00:00Commented Apr 1, 2011 at 21:46
-
thanks for the comment along with @Gilles observation I got it to work.Azim– Azim2011年04月01日 21:58:12 +00:00Commented Apr 1, 2011 at 21:58
The answer @SiegeX presents will work, but if you have a lot of files in your pattern file, this might become slow and clumsy. You might get much better performance by using a different tool, like this:
find . | grep -f pattern.txt
Yup, that was the whole thing.
You must log in to answer this question.
Explore related questions
See similar questions with these tags.
pattern.txt
be a DOS/Windows text file, which to unix tools looks like each line ends with a CR character? If so, this command would look for files with a CR in their name. Runcat -A pattern.txt
to check that it does indeed contain only letters (you should see lines likefoobar$
, norfoobar^M$
).