find' (command) finds nothing with -wholename
The first command generates file names starting with ./../..
. Thus the wholename pattern will match because they start with .
.
The second command generates filenames starting with /home
. However, the wholename pattern is still looking for paths starting with .
which will not match any file in this case.
Note that patterns are not regular expressions. If you were expecting them, look at the -regex
option instead.
Find command works in terminal but not in bash script
The command find ./bin -wholename './bin/backup2' -prune -o -wholename './bin/backup3' -prune -o -print
should work as intended, provided the current directory is directly above bin/
. This may be the cause of your problems: If in the real script you assemble path names which do not match the prefixes in the found paths then e.g. the prune will not work. Example: You have a dir /home/me
; in it is bin/backup2/
, bin/backup3/
and stuff-to-backup/
. Now if you are in /home/me
and execute find .
it finds e.g. ./bin/backup2
which will be pruned.
But if you put this in a script and call the script with path arguments, e.g. /home/me
, it will find the same files but the paths will be different, e.g. /home/me/bin/backup2
, and will not prune it because it does not match the supplied exclude pattern, even though they are the same files. Likewise no patterns supplied with -wholename
will be found. Here is a question which addresses this problem.
How to use regex with find command?
find . -regextype sed -regex ".*/[a-f0-9\-]\{36\}\.jpg"
Note that you need to specify .*/
in the beginning because find
matches the whole path.
Example:
susam@nifty:~/so$ find . -name "*.jpg"
./foo-111.jpg
./test/81397018-b84a-11e0-9d2a-001b77dc0bed.jpg
./81397018-b84a-11e0-9d2a-001b77dc0bed.jpg
susam@nifty:~/so$
susam@nifty:~/so$ find . -regextype sed -regex ".*/[a-f0-9\-]\{36\}\.jpg"
./test/81397018-b84a-11e0-9d2a-001b77dc0bed.jpg
./81397018-b84a-11e0-9d2a-001b77dc0bed.jpg
My version of find:
$ find --version
find (GNU findutils) 4.4.2
Copyright (C) 2007 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Eric B. Decker, James Youngman, and Kevin Dalley.
Built using GNU gnulib version e5573b1bad88bfabcda181b9e0125fb0c52b7d3b
Features enabled: D_TYPE O_NOFOLLOW(enabled) LEAF_OPTIMISATION FTS() CBO(level=0)
susam@nifty:~/so$
susam@nifty:~/so$ find . -regextype foo -regex ".*/[a-f0-9\-]\{36\}\.jpg"
find: Unknown regular expression type `foo'; valid types are `findutils-default', `awk', `egrep', `ed', `emacs', `gnu-awk', `grep', `posix-awk', `posix-basic', `posix-egrep', `posix-extended', `posix-minimal-basic', `sed'.
Strange behaviour of UNIX find command
The -wholepath
, as name implies, matches the whole name of the element. See man find
for the description of the -path
option (which has made the -wholepath
obsolete).
What you want is something like this:
find ./* -type d -path "*/lib/bin"
How can I find a file/directory that could be anywhere on linux command line?
"Unfortunately this seems to only check the current directory, not the entire folder". Presumably you mean it doesn't look in subdirectories. To fix this, use find -name "filename"
If the file in question is not in the current working directory, you can search your entire machine via
find / -name "filename"
This also works with stuff like find / -name "*.pdf"
, etc. Sometimes I like to pipe that into a grep statement as well (since, on my machine at least, it highlights the results), so I end up with something like
find / -name "*star*wars*" | grep star
Doing this or a similar method just helps me instantly find the filename and recognize if it is in fact the file I am looking for.
find command works on prompt, not in bash script - pass multiple arguments by variable
You're running into an issue with how the shell handles variable expansion. In your script:
includeString="-wholename './public_html/*' -o -wholename './config/*'"
find . \( $includeString \) -type f -mtime -7 -print
This results in find
looking for files where -wholename
matches the literal string './public_html/*'
. That is, a filename that contains single quotes. Since you don't have any whitespace in your paths, the easiest solution here would be to just drop the single quotes:
includeString="-wholename ./public_html/* -o -wholename ./config/*"
find . \( $includeString \) -type f -mtime -7 -print
Unfortunately, you'll probably get bitten by wildcard expansion here (the shell will attempt to expand the wildcards before find
sees them).
But as Etan pointed out in his comment, this appears to be needlessly complex; you can simply do:
find ./public_html ./config -type f -mtime -7 -print
How do I prevent find from printing .git folders?
Try this one:
find . -name '*foo*' | grep -v '\.git'
This will still traverse into the .git directories, but won't display them. Or you can combine with your version:
find . ( -name .git ) -prune -o -name '*foo*' | grep -v '\.git'
You can also do it without grep:
find . ( -name .git ) -prune -printf '' -o -name '*foo*' -print
Find files with brackets in their names with -iwholename
In my man find
page in BSD I see:
-path pattern
True if the pathname being examined matches pattern. Special
shell pattern matching characters (``['', ``]'', ``*'', and
``?'') may be used as part of pattern. These characters may be
matched explicitly by escaping them with a backslash (``\'').
Slashes (``/'') are treated as normal characters and do not have
to be matched explicitly.
(and -path
is the same as -wholename
and -iwholename
is the same as -path
but case insensitive)
You have to escape these characters because they have special meaning to the shell otherwise. This is the same for other flags like -name
and -iname
.
To make your find
work with arbitrary strings, you need to escape these special characters, for example like this:
escaped=$(sed -e 's/[][?*]/\\&/g' <<< "*aoeu*")
find ./ -iwholename "$escaped"
UPDATE
As you yourself figured out, if you need to replace a lot of patterns per second, it will be more efficient to use bash
to do the replacement instead of spawning a sed
every time, like this:
filename_escaped="${filename//\[/\\[}"
filename_escaped="${filename_escaped//\]/\\]}"
filename_escaped="${filename_escaped//\*/\\*}"
filename_escaped="${filename_escaped//\?/\\?}"
Related Topics
How to Force a Range of Virtual Addresses
Mono and Unmanaged Code in Ubuntu
Extract Parent Domain Name from a List of Url Through Bash Shellscripting
Run 'Perf Stat' on The Output of 'Perf Record'
How to Have Postgresql Not Collapse Punctuation and Spaces When Collating Using a Language
Socket Programming Send() Return Value
Linux Shell Kill Signal Sigkill && Kill
Apache/Httpd /Var/Www/HTML/ .Cgi Scripts Throw 500 Internal Server Error
What Means "Atomic" System Call
Linux/Cygwin Recursively Copy File Change Extension
Can't Install Using Yum in Rhel 7.1
Is There a Rpm File Naming Convention in Lsb
How to Convert Absolute Path to Relative in C Linux
Reason of a Directory Size Being Zero