wild cards on find and ls - linux

I'm trying to figure out the wild-cards to do file operations.
I have these files in a directory for testing purposes:
file_BSD.GIF file_linux.gif file_unix
See my ls command,
$ ls *{.GIF,.gif}
file_BSD.GIF file_linux.gif
Which is OK.
But "find" doesn't seem to work the same way:
$ find -name *{.GIF,.gif}
find: paths must precede expression: file_linux.gif
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
By the way, I've read that "-iname" should locate both the uppercase and lowercase files, but that doesn't seem to work either:
$find -iname *.gif
./file_linux.gif
(This should locate the .GIF file as well, right?).

find -name *{.GIF,.gif} is wrong.
This command is first expanded by the shell to find -name *.GIF *.gif
Then further expanded to :
find -name file_BSD.GIF file_linux.gif
# as you have only these files in directory
Now this -name file_BSD.GIF file_linux.gif is passed to find. And this is wrong as there is no switch like file_linux.gif that is accepted by find.
What you need is this command.
find -name '*.GIF' -or -name '*.gif'
Assuming you want to collect .gif files in a case insensitive manner, this find command becomes,
find -iname '*.gif'
Note the single quotes (') here. It means *.GIF should be sent to find as is without any shell expansion. And find will use this as pattern. This single quote is necessary unless you escape the shell meta-characters. In that case the command would look like
find -iname \*.gif

You are having trouble with the parameter -iname of find because you must quote the patterns you give to it.
So, you should do:
find -iname '*.gif'
This is stated in the manual:
"... Please note that you should quote patterns as a matter of course, otherwise the shell will expand any wildcard characters in them."

You should understand that (in contrast to Windows) the shell is expanding the *{.GIF,.gif} before passing it to the find program.
You can feel what the shell does by replacing the program with echo.
So you should quote the program argument, like
echo \-name '*{.GIF,.gif}'
so run
find -name '*.{GIF,gif}'
Maybe you want
find -name '*.gif' -o -name '*.GIF'
Please read the Advanced Bash Scripting Guide (and perhaps the execve(2) man page, to understand how the kernel run programs).

Related

Can't find a file by pattern [duplicate]

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

How do I find a file containing using wildcard on Linux?

I would like to know if it is possible to use find with wildcards:
I use this command, but I have an error
find -type f -name /target/*.zip
You need to put the wildcard in quotes, otherwise it gets expanded by the shell before the command is run.
And it should just be a filename, not a pathname. The directory to start searching should be an argument to find before the filter specifications.
find /target -type f -name '*.zip'

Linux find command shell expansion

I have just a little question I don't understand with the find command.
I can do this :
[root#hostnaoem# ❯❯❯ls /proc/*/fd
But this give me an error :
[root#hostnaoem# ❯❯❯ find /proc/*/fd -ls
find: `/proc/*/fd': No such file or directory
even if I use "/proc//fd", /proc/""/fd or "/proc/*/fd"
I've searched wha find shell expansion says about that, but I found nothing. Can someone tell me why?
Thanks
If you just RTFM, you'll learn that the syntax for find is:
find [-H] [-L] [-P] [-D debugopts] [-Olevel] [path...] [expression]
The usually used subset of that is:
find whereToSearch (-howToSearch arg)*
To find all files|directories named fd in /proc:
find /proc -name fd
-name is the most common howToSearch expression:
-name pattern
Base of file name (the path with the leading directories
removed) matches shell pattern pattern. The metacharacters
(`*', `?', and `[]') match a `.' at the start of the base name
(this is a change in findutils-4.2.2; see section STANDARDS CON‐
FORMANCE below). To ignore a directory and the files under it,
use -prune; see an example in the description of -path. Braces
are not recognised as being special, despite the fact that some
shells including Bash imbue braces with a special meaning in
shell patterns. The filename matching is performed with the use
of the fnmatch(3) library function. Don't forget to enclose
the pattern in quotes in order to protect it from expansion by
the shell.
(Note the the last sentence)
If your pattern contains slashes, you need -path or -wholename (same thing):
find /proc/ -wholename '/proc/[0-9]*/fd' 2>/dev/null
Other expressions you might want to use are:
-type
-depth, -mindepth, -maxdepth
-user, -uid
See find(1) to learn more about each search expressions. If you want to search the in-terminal manual (man find or man 1 find), you can use the / character to enter search mode (like Ctrl+F in most GUI apps).
Usage of ls with globbing (*) is generally a code smell. Unless you use the -d flag, it'll list the contents of the directories that match the glob pattern in addition to the matches.
I find the echo globpattern form generally more convenient for viewing the results of a glob pattern match.
This work :
[root#hostname # ❯❯❯ find /proc/ -path /proc/*/fd -ls
Regards.

Why does find . -name foo* fail?

OK, probably a stupid question, but why doesn't this work?
find . -name Orna* -ls
It seems that "find" should be able to handle this simple request... Am I missing something here? This should be a basic execution of the "find" command, but linux is being stupid, or maybe I am.
correct way of using Find Command are the following phrases
find . -type f -name "filename" # this command used to find files from the curent dir
find . -type d -name "dir name" # this command used to find dirs from the curent dir
find /. -type f -name "filename" # this command used to find files from the system
find /. -type d -name "dir name" # this command used to find dirs from the system
I wish it be a helpful for you
You need to quote the name parameter so the shell doesn't expand the wildcard, e.g.
find . -name "Orna*" -ls
To explain the "why" a little more than existing answers do -- wildcards are expanded by the shell before the command being invoked is run. Thus, let's say your current directory contains files Orna1 and Orna2.
In that case, when you run
find . -name Orna* -ls
...what's actually invoked by the shell is:
find . -name Orna1 Orna2 -ls
...thus, find never sees the wildcard expression at all!
Quoting the expansion, as in:
find . -name 'Orna*' -ls
...prevents the shell from trying to expand the wildcard before running your command, thus preventing this issue.

A question about command "find"

find . \( -name "_*" -or -newer while2 \) -type f -print
In the linux command above , why _* should be quoted ?
First, the shell expands all unquoted *'s to match file names in the local directory.
After that, the shell runs the find command with that list of file names.
Generally, you don't want the shell to do '*' globbing in the local directory. Generally, you wind the find command to do filename matching in other directories.
The shell has several other things it does before running a command. $VARIABLE replacement is one of those.
Why _* should be quoted ?
If it isn't, your shell might expand the * to be substituted with files in the current directory. That's probably not what you wanted here.
if you don't quote it, the shell (bash?) would try to expand. if there's any file that starts with '_' on the current directory, you'd get something like:
find . \(-name _somefile _someother _file3 .... -or -newer while2 \) -type f -print
certainly not what you want. i always quote patterns, just to be sure the shell won't mess with them

Resources