Can't find a file by pattern [duplicate] - linux

I am having a hard time getting find to look for matches in the current directory as well as its subdirectories.
When I run find *test.c it only gives me the matches in the current directory. (does not look in subdirectories)
If I try find . -name *test.c I would expect the same results, but instead it gives me only matches that are in a subdirectory. When there are files that should match in the working directory, it gives me: find: paths must precede expression: mytest.c
What does this error mean, and how can I get the matches from both the current directory and its subdirectories?

Try putting it in quotes -- you're running into the shell's wildcard expansion, so what you're acually passing to find will look like:
find . -name bobtest.c cattest.c snowtest.c
...causing the syntax error. So try this instead:
find . -name '*test.c'
Note the single quotes around your file expression -- these will stop the shell (bash) expanding your wildcards.

What's happening is that the shell is expanding "*test.c" into a list of files. Try escaping the asterisk as:
find . -name \*test.c

From find manual:
NON-BUGS
Operator precedence surprises
The command find . -name afile -o -name bfile -print will never print
afile because this is actually equivalent to find . -name afile -o \(
-name bfile -a -print \). Remember that the precedence of -a is
higher than that of -o and when there is no operator specified
between tests, -a is assumed.
“paths must precede expression” error message
$ find . -name *.c -print
find: paths must precede expression
Usage: find [-H] [-L] [-P] [-Olevel] [-D ... [path...] [expression]
This happens because *.c has been expanded by the shell resulting in
find actually receiving a command line like this:
find . -name frcode.c locate.c word_io.c -print
That command is of course not going to work. Instead of doing things
this way, you should enclose the pattern in quotes or escape the
wildcard:
$ find . -name '*.c' -print
$ find . -name \*.c -print

Try putting it in quotes:
find . -name '*test.c'

I see this question is already answered. I just want to share what worked for me. I was missing a space between ( and -name. So the correct way of chosen a files with excluding some of them would be like below;
find . -name 'my-file-*' -type f -not \( -name 'my-file-1.2.0.jar' -or -name 'my-file.jar' \)

I came across this question when I was trying to find multiple filenames that I could not combine into a regular expression as described in #Chris J's answer, here is what worked for me
find . -name one.pdf -o -name two.txt -o -name anotherone.jpg
-o or -or is logical OR. See Finding Files on Gnu.org for more information.
I was running this on CygWin.

You can try this:
cat $(file $( find . -readable) | grep ASCII | tr ":" " " | awk '{print $1}')
with that, you can find all readable files with ascii and read them with cat
if you want to specify his weight and no-executable:
cat $(file $( find . -readable ! -executable -size 1033c) | grep ASCII | tr ":" " " | awk '{print $1}')

In my case i was missing trailing / in path.
find /var/opt/gitlab/backups/ -name *.tar

Related

Unix brace expansion within find command

This is working fine:
$ echo email_{ldn,nyk,asp}.log
Similarly, I wanted to find filenames which differ slightly:
$ find ~ -type f -name email_{ldn,nyk,asp}.log
But above command results in error:
find: paths must precede expression: email_nyk.log
Any help on brace expansions within find command will be very much appreciated.
The error message results from the expansion of the pattern by your shell.
Assuming you have the files email_ldn.log, email_nyk.log and email_asp.log in your current directory, your command
find ~ -type f -name email_{ldn,nyk,asp}.log
will be expanded to
find ~ -type f -name email_ldn.log email_nyk.log email_asp.log
which results in the error message.
To prevent the expansion of a pattern by the shell you have to quote the pattern. Unfortunately, find doesn't support patterns with a list of alternatives in braces, so using this pattern with find will not work as you might expect.
find ~ -type f -name "email_{ldn,nyk,asp}.log" # Does not work as intended.
find ~ -type f -name "email_*.log" # This would work, but matches other files as well.
If you have GNU find, you could use a regular expression instead.
find ~ -type f -regextype posix-extended -regex ".*/email_(ldn|nyk|asp).log"
Brace expansion is not the way to do this sort of thing, and eval is evil, but you could do:
eval find ~ -type f -and \\\( -false "-or -name "email_{ldn,nyk,asp}.log \\\)
The main idea is that -name email_ldn.log email_nyk.log email_asp.log does not work, because you want the expression to be -name email_ldn.log -or -name email_nyk.log -or -name email_asp.log, so you create that expression with the brace expansion. But then find receives -or -name email_???.log as a single argument instead of 3 arguments, so you need to force word splitting with eval. Overall, a nasty, ugly solution.
If you want to find all files with one prefix you can use this command:
find ~ -type f -name "email_*.log"
In this situation you don't need to use braces. Don't forget to put " (quotes) before and after the pattern of the name.
find doesn't support braces to set alternatives, like the shell does. So, if you want to find specific files, you can do this in 2 steps: first find all files with 'email' prefix and then grep for specific files. Try this:
find ~ -type f -name "email*" | egrep "email_(ldn|asp|nyk).log"
It was realized eventually during the conquest, some of you have suggested using eval, but I think it would better to use xargs :
As the aim is to find files matching the brace expansion and execute few command thereafter, so xargs suites this purpose nicely.
$ ls ~/email_{ldn,nyk,asp}.log | xargs -I %% sh -c 'chomd 644 %% && cp -arf %% ~/feed_dir'

Recursively find files with a specific extension

I'm trying to find files with specific extensions.
For example, I want to find all .pdf and .jpg files that's named Robert
I know I can do this command
$ find . -name '*.h' -o -name '*.cpp'
but I need to specify the name of the file itself besides the extensions.
I just want to see if there's a possible way to avoid writing the file name again and over again
Thank you !
My preference:
find . -name '*.jpg' -o -name '*.png' -print | grep Robert
Using find's -regex argument:
find . -regex '.*/Robert\.\(h\|cpp\)$'
Or just using -name:
find . -name 'Robert.*' -a \( -name '*.cpp' -o -name '*.h' \)
find -name "*Robert*" \( -name "*.pdf" -o -name "*.jpg" \)
The -o repreents an OR condition and you can add as many as you wish within the braces. So this says to find all files containing the word "Robert" anywhere in their names and whose names end in either "pdf" or "jpg".
As an alternative to using -regex option on find, since the question is labeled bash, you can use the brace expansion mechanism:
eval find . -false "-o -name Robert".{jpg,pdf}
This q/a shows how to use find with regular expression: How to use regex with find command?
Pattern could be something like
'^Robert\\.\\(h|cgg\\)$'
As a script you can use:
find "${2:-.}" -iregex ".*${1:-Robert}\.\(h\|cpp\)$" -print
save it as findcc
chmod 755 findcc
and use it as
findcc [name] [[search_direcory]]
e.g.
findcc # default name 'Robert' and directory .
findcc Joe # default directory '.'
findcc Joe /somewhere # no defaults
note you cant use
findcc /some/where #eg without the name...
also as alternative, you can use
find "$1" -print | grep "$#"
and
findcc directory grep_options
like
findcc . -P '/Robert\.(h|cpp)$'
Using bash globbing (if find is not a must)
ls Robert.{pdf,jpg}
Recurisvely with ls: (-al for include hidden folders)
ftype="jpg"
ls -1R *.${ftype} 2> /dev/null
For finding the files in system using the files database:
locate -e --regex "\.(h|cpp)$"
Make sure locate package is installed i.e. mlocate

Yjw to replace and then search with sed and find

I'm making a bash script which would call like
script.sh 172.16.1.1
trying to replace . and search files to delete them but it won't happen
echo $1 | find -name '*.`sed 's/\.*//g'`' -printf "%f\n" -delete
files look like
eth0-2:120.1721611 eth1-2:120.1721611
Try this command inside that script.
I think this may help you for your requirement.
$ find -name "*echo "$1" | sed 's/\.*//g'" -printf "%f\n" -delete
I am passing the name only for the particular field, If you passed for whole command it produce the different result.
The given command is searched from current directory to end.
If you need to search from root or home use / or ~ in find command like
$ find ~ -name "*echo "$1" | sed 's/\.*//g'" -printf "%f\n" -delete

Unix display info about files matching one of two patterns

I'm trying to display on a Unix system recursively all the files that start with an a or ends with an a with some info about them: name, size and last modified.
I tried find . -name "*a" -o -name "a*" and it displays all the files okay but when I add -printf "%p %s" it displays only one result.
If you want the same action to apply to both patterns, you need to group them with parentheses. Also, you should add a newline to printf, otherwise all of the output will be on one line:
find . \( -name "*a" -o -name "a*" \) -printf "%p %s\n"
find . -name "*.c" -o -name "*.hh" | xargs ls -l | awk '{print $9,$6,$7,$8,$5}'

Linux: Redirecting output of a command to "find"

I have a list of file names as output of certain command.
I need to find each of these files in a given directory.
I tried following command:
ls -R /home/ABC/testDir/ | grep "\.java" | xargs find /home/ABC/someAnotherDir -iname
But it is giving me following error:
find: paths must precede expression: XYZ.java
What would be the right way to do it?
ls -R /home/ABC/testDir/ | grep -F .java |
while read f; do find . -iname "$(basename $f)"; done
You can also use ${f##*/} instead of basename. Or;
find /home/ABC/testDir -iname '*.java*' |
while read f; do find . -iname "${f##*/}"; done
Note that, undoubtedly, many people will object to parsing the output of ls or find without using a null byte as filename separater, claiming that whitespace in filenames will cause problems. Those people usually ignore newlines in filenames, and their objections can be safely ignored. (As long as you don't allow whitespace in your filenames, that is!)
A better option is:
find /home/ABC/testDir -iname '*.java' -exec find . -iname {}
The reason xargs doesn't work is that is that you cannot pass 2 arguments to -iname within find.
find /home/ABC/testDir -name "\.java"

Resources