Find' (Command) Finds Nothing with -Wholename

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



Leave a reply



Submit